Amazon Aurora Global Databaseの書き込み転送機能を使ってセカンダリ・リージョンから書き込んでみた

2021.04.21

Amazon Aurora Global Database を利用すると、Amazon Aurora クラスターを複数の AWS リージョンにまたがって構築できます。

初期設定では、Aurora Global Database はプライマリリージョンでのみ書き込み可能です。

グローバルに展開するサービスにおいて、読み込みはローカルリージョン、書き込みはプライマリリージョンに分けると、整合性の管理が難しくなったり、遠方にあるプライマリリージョンへ通信する際の高いレイテンシーが問題になります。

書き込み転送機能を使用することで、ユーザー最寄りのリージョンに対して読み書きを透過的に処理し、レイテンシーを下げることが期待できます。

この書き込み転送機能を触ってみます。

やってみた

書き込み転送機能を利用するには、以下の3ステップが必要です。

  1. Aurora Global Database を複数リージョンで構築
  2. セカンダリ・リージョンで書き込み転送を有効化
  3. Reader エンドポイントに対して読み書きSQLを実行

1. Aurora Global Database を複数リージョンで構築

Aurora Global Database を複数リージョンにまたがって構築します。

書き込み転送は Aurora MySQL 5.7 系の 2.08.1 以降である必要があります。

Aurora MySQL 5.6 系や Aurora PostgreSQL 系は利用できないため、ご注意ください。

検証では以下を利用しました。

  • エンジンバージョン : Aurora MySQL 5.7 系の 2.08.3
  • インスタンスタイプ : r5.large

2. セカンダリ・リージョンで書き込み転送を有効化

Aurora Global Database は

  • 読み書き可能なプライマリ・リージョン
  • 初期状態では読み取りのみ可能なセカンダリ・リージョン

の2種類のリージョンがあります。

書き込み転送機能はセカンダリ・リージョンに対してクラスター単位で設定します。

書き込み転送を有効にしたいセカンダリ・リージョンのクラスター変更画面から「リードレプリカの書き込み転送」のチェックボックスを有効にします。

3. Reader エンドポイントに対して読み書きSQLを実行

書き込み転送を有効にしても、セカンダリリージョンで利用可能なエンドポイントは、「読み込み」用だけです。

アプリケーションの読み書きのエンドポイントをこの「読み込み」用エンドポイントに向けます。

ただし、この「読み込み」用エンドポイントで書き込むには、セッションごとに整合性(aurora_replica_read_consistency)を指定する必要があります。

この整合性の指定について以降で説明します。

書き込み転送有効時の整合性指定について

セカンダリリージョンで書き込み転送を有効にしただけでは、デフォルトでは読み込みしかできません。

MySQL [test]> insert into foo values(1);
ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement

セッション内で整合性(aurora_replica_read_consistency)を指定すること、書き込めるようになります。

MySQL [test]> set aurora_replica_read_consistency = 'session';
Query OK, 0 rows affected (0.00 sec)

MySQL [test]> insert into foo values(1);
Query OK, 1 row affected (0.22 sec)

整合性レベルは

  • 結果整合性(eventual)
  • セッション内整合性(session)
  • グローバル整合性(global)

の3種類があります。

整合性レベル 整合性 書き込み待ち時間 データの見え方
EVENTUAL 短い 更新の反映は一切待たない。プライマリに書き込み転送後、セカンダリにレプリケートされると読み取れる。
SESSION 同一セッション内の更新は、トランザクションのコミット前であっても読み取れる。他リージョン、同一リージョンの他セッションの更新反映は待たない。
GLOBAL 長い 読み込み開始時点のプライマリリージョンのコミット済みデータの反映を待つ。

簡単に各整合性レベルの動作を確認します。

結果整合性(eventual)

結果整合性では、更新の反映は一切待ちません。プライマリに書き込み転送後、セカンダリにレプリケートされると読み取れるようになります。

書き込みが成功したことを確認できれば十分であり、書き込み内容を後続処理で即座に利用しないケースに向いています。

テーブルにレコードを追加する前後で、テーブル内のレコード件数を確認します。

セッションの整合性を結果整合性(eventual)に設定します。

MySQL [test]> set aurora_replica_read_consistency = 'eventual';
Query OK, 0 rows affected (0.00 sec)

初期状態ではレコード件数は 0 件です。

MySQL [test]> select count(*) from foo;
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.01 sec)

レコード追加直後の読み取り時間は 0.00 秒と高速ですが、レコード追加が反映されておらず、レコード件数が 0 件のままです。

MySQL [test]> insert into foo values(1);
Query OK, 1 row affected (0.23 sec)

MySQL [test]> select count(*) from foo;
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

3秒後に再確認すると、正しく1件に増えていました。

結果整合性になっています。

MySQL [test]> select sleep(3);
+----------+
| sleep(3) |
+----------+
|        0 |
+----------+
1 row in set (3.00 sec)

+----------+
| count(*) |
+----------+
|        1 |
+----------+
1 row in set (0.00 sec)

セッション整合性(session)

セッション整合性では、同一セッション内の更新は、トランザクションのコミット前であっても読み取れます(read-your-writes consistency)。 ただし、他リージョン、同一リージョンの他セッションの更新反映は待ちません。

整合性をセッション整合性(session)に設定します。

MySQL [test]> set aurora_replica_read_consistency = 'session';
Query OK, 0 rows affected (0.00 sec)

レコード追加前のレコード件数は1件です。

MySQL [test]> select count(*) from foo;
+----------+
| count(*) |
+----------+
|        1 |
+----------+
1 row in set (0.00 sec)

レコード追加直後に読み取ると、期待通りレコード件数が1件増えています。 ただし、読み取り時間が 結果整合性時代の 0秒 から 0.99 秒に伸びています。

MySQL [test]> insert into foo values(1);
Query OK, 1 row affected (0.23 sec)

MySQL [test]> select count(*) from foo;
+----------+
| count(*) |
+----------+
|        2 |
+----------+
1 row in set (0.99 sec)

グローバル整合性(global)

最後にグローバル整合性を試します。

グローバル整合性は、読み込み開始時点のプライマリリージョンのコミット済みデータの反映を待ちます。 最高レベルの整合性を担保できる一方で、読み取り時間が大幅に伸びます。

整合性をグローバル整合性(global)に設定します。

MySQL [test]> set aurora_replica_read_consistency = 'global';
Query OK, 0 rows affected (0.01 sec)

レコード追加前のレコード件数は2件です。 読み取りに 1.62 秒もかかっています。

MySQL [test]> select count(*) from foo;
+----------+
| count(*) |
+----------+
|        2 |
+----------+
1 row in set (1.62 sec)

レコード追加直後に読み取ると、レコード件数が1件増えています。 ただし、読み取り時間が 2.80 秒です。

結果整合性の 0.00秒、セッション整合性の 0.99 秒よりも大幅に伸びています。

MySQL [test]> insert into foo values(1);
Query OK, 1 row affected (0.23 sec)

MySQL [test]> select count(*) from foo;

+----------+
| count(*) |
+----------+
|        3 |
+----------+
1 row in set (2.80 sec)

Aurora Global Database で利用可能なトランザクション

Aurora Global Database で利用可能なトランザクションは通常のAuroraと同じです。 ただし、書き込み転送が有効なリーダーは REPEATABLE READ しか利用できません。

タイプ ロール REPEATABLE READ READ COMMITTED READ UNCOMMITTED SERIALIZABLE
regional writer YES YES YES YES
regional reader YES YES(Session Level)
global writer YES YES YES YES
global reader YES YES(Session Level)
secondary reader YES YES(Session Level)
secondary write fwd reader YES

SQL の制限

書き込み転送では、一般的な DML 文の他、 トランザクション文、SELECT ... FOR UPDATE 節を使った行ロックなどが使えます。

例えば、次のような read-modify-write 処理も記述できます。

BEGIN TRANSACTION;

SELECT * FROM tbl
WHERE some_condition
FOR UPDATE;

UPDATE tbl SET foo = bar;
COMMIT;

ただし、DDL文、LOAD DATA 文、XA トランザクション などは利用できません。

詳細はドキュメントをご確認ください。

最後に

グローバルに展開するサービスで Aurora Global Database を複数リージョンに展開し、書き込み転送機能を使用すると、ユーザー最寄りのリージョンに対して読み書きを透過的に処理し、レイテンシーを下げることが期待できます。

リーダーエンドポイントへの書き込み時にはセッション単位で整合性を指定する必要があり、この整合性レベルによって読み取り速度が大きくかわります。

システムや書き込む機能が要求する整合性をよく精査した上で、適切な整合性レベルを選択してください。

『データ指向アプリケーションデザイン』の 7〜9章を読むと、整合性やトランザクションへの理解が深まるので、一読をおすすめします。

参考