ビデオリサーチ公式テックブログ

ビデオリサーチ公式テックブログ

Aurora MySQLクラスターのローカル (クラスター内) 書き込み転送機能の整合性レベルについて調べてみた

こんにちは。株式会社ビデオリサーチのキクチです。
突然ですが、皆さんはAmazon Auroraのリードレプリカ運用はどうされていますか?
アプリケーション側でリーダー/ライターのエンドポイントを制御したり、CQRSパターンでの実装をされる方も多いことでしょう。

本題に入りますが、今年の7月にAurora MySQLでローカル (クラスター内) 書き込み転送がサポートされましたね。この機能を有効にすると、アプリケーションはリードレプリカからも書き込みトランザクションの発行が可能となります。
aws.amazon.com docs.aws.amazon.com

リードレプリカを導入する際、冒頭のようにアプリケーションでの対応が出来れば良いですが、レガシーな構成の環境では運用が難しい場合もあり、このアップデートが気になっていた方もいらっしゃるのではないかと思います。

公式ドキュメントにもある通り、こちらの機能の利用にあたっては、(転送した書き込みデータの)読み取り整合性レベルの指定が必須となります。
今回はこの書き込み転送機能の整合性レベルについて検証してみました。

検証環境

  • エンジンバージョン
    • Aurora MySQL 3.04.1 (compatible with MySQL 8.0.28)
      • (※ローカル書き込み転送機能は3.04.0から利用可能)
  • インスタンス
    • db.t3.medium
  • マルチAZ DBクラスタ
    • Writer :ap-northeast-1a
    • Reader:ap-northeast-1b
    • Reader:ap-northeast-1c
  • 検証用テーブル
    • 以下のような簡易テーブルを作成
CREATE TABLE users (
  id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
  name varchar(32) NOT NULL,
  description varchar(64)
);

整合性レベルの検証

Aurora クラスターパラメータグループの「aurora_replica_read_consistency」から書き込み転送の読み取り整合性レベルを指定します。
整合性レベルには以下の3種類を指定可能です。
「eventual」「session」「global」
以下で、各整合性レベルについて動作を検証してみます。

eventual

3つのオプションの中では最も弱い整合性レベルで、リーダーからのデータ更新の順序は保証されません。いわゆる、結果整合性です。
以下のようなクエリを用意し実行してみます。

INSERT INTO users (name, description) VALUES ('tanaka', 'eventual');
INSERT INTO users (name, description) VALUES ('yamada', 'eventual');
update users set description='updated' where name='tanaka';  
select * from users;
mysql> source /xxxxx/xxxxxx/replica-test/eventual_read_test.sql
Query OK, 1 row affected (0.01 sec)

Query OK, 1 row affected (0.01 sec)

Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0

+----+--------+-------------+
| id | name   | description |
+----+--------+-------------+
|  1 | tanaka | eventual    |
|  2 | yamada | eventual    |
+----+--------+-------------+
2 rows in set (0.01 sec)

3行目のupdateの更新が反映されていないことが分かります。 少し時間を置いて、再度selectすると全ての書き込みが反映されていました。

mysql> select * from users;
+----+--------+-------------+
| id | name   | description |
+----+--------+-------------+
|  1 | tanaka | updated     |
|  2 | yamada | eventual    |
+----+--------+-------------+
2 rows in set (0.01 sec)

アプリケーション側の仕組みで弱い整合性を受け入れられる環境でないと、導入は難しそうですね。

session

公式ドキュメントを見ると、
「書き込み転送を使用するすべてのクエリには、そのセッションで行われたすべての変更の結果が表示されます。トランザクションがコミットされているかどうかにかかわらず、変更が表示されます。必要に応じて、クエリは、転送された書き込み操作の結果がレプリケートされるまで待機します。」 とあります。
要約すると、同一セッション内で行われた書き込み操作に限ってデータ更新の順序を保証します、ということのようです。

同じようにリードレプリカに対して、以下のようなクエリを用意し実行してみます。

INSERT INTO users (name, description) VALUES ('suzuki', 'session');
INSERT INTO users (name, description) VALUES ('sato', 'session');
update users set description='updated' where name='suzuki';  
select * from users;
mysql> source /xxxxx/xxxxxx/replica-test/session_read_test.sql
Query OK, 1 row affected (0.01 sec)

Query OK, 1 row affected (0.02 sec)

Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0

+----+--------+-------------+
| id | name   | description |
+----+--------+-------------+
|  1 | tanaka | updated     |
|  2 | yamada | eventual    |
|  3 | suzuki | updated     |
|  4 | sato   | session     |
+----+--------+-------------+
4 rows in set (0.02 sec)

今度は全ての書き込みが反映されていることが分かります。レイテンシの悪化もほとんど無さそうです。

global

3つの中で最も高い整合性レベルで、すべての書き込み操作のデータ更新順序が保証されるオプションです。
アプリケーション側で弱い整合性を受け入れられない場合は、このオプション一択になるのではないでしょうか。
同様にリードレプリカで以下のようなクエリを実行してみます。

INSERT INTO users (name, description) VALUES ('takahashi', 'global');
INSERT INTO users (name, description) VALUES ('watanabe', 'global');
update users set description='updated' where name='takahashi';  
select * from users;
mysql> source /xxxxx/xxxxxx/replica-test/global_read_test.sql
Query OK, 1 row affected (0.02 sec)

Query OK, 1 row affected (0.02 sec)

Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

+----+-----------+-------------+
| id | name      | description |
+----+-----------+-------------+
|  1 | tanaka    | updated     |
|  2 | yamada    | eventual    |
|  3 | suzuki    | updated     |
|  4 | sato      | eventual    |
|  5 | takahashi | updated     |
|  6 | watanabe  | global      |
+----+-----------+-------------+
6 rows in set (0.03 sec)

session同様、全ての書き込みが反映されていますね。かつ、レイテンシの悪化もほとんど無く高速です。

おわりに

公式ドキュメントには、強い整合性レベルを指定した場合はレプリケーションラグによる長めの待機時間が発生する旨の記載があるので、ある程度のレイテンシの悪化を予想していましたが、実際には悪化はほとんど見られず素晴らしい結果となりました。
データ量が増えるなどした場合、また結果が変わってくるのかもしれませんが、リードレプリカの運用に苦労されている方、導入を見送られていた方などは一考の余地があるのではないでしょうか。