JINSのアーキテクチャ設計の最近のテーマの一つに、データベースのグローバル対応をどうするか?というのがあります。JINSは、グローバルに展開するアイウエアの製造小売の会社でして、いろんな国に事業展開していますが、それぞれのシステムはローカライズしたり、共通化したり色々です。
現在、クラウドネイティブ化を進めていて、システム基盤をグローバル共通化していく方針としています。アーキテクチャ設計で言えば、機能配置とデータ配置をどうしていくかという事になりますが、今回の投稿はデータベースについて書いてみたいと思います。
Amazon Aurora Global Databaseはどんなもの?
みなさんは、Amazon AuroraとAmazon RDSはどのように使い分けてますか?
トランザクション規模やコストなど色々な観点があると思いますが、JINSとしては、Amazon Auroraを使い倒していこうと思っています。
https://aws.amazon.com/jp/rds/aurora/features/
Amazon Auroraには、Amazon Aurora Global Databaseというサービスがあって、これはクロスリージョンでデータベースの対策を取りたい場合に有用です。データベースは耐障害性や可用性が重要となるので、マルチAZであることは当たり前な要件だと思いますが、これをもっと広くリージョン跨ぎで考慮したい場合に良い選択肢となります。
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/aurora-global-database.html#aurora-global-database-overview
データベース設計においては書き込み処理と読み込み処理のスループットについて考慮しなければいけませんが、Amazon Aurora Global Databaseは、プライマリDBクラスタのリージョンとセカンダリDBクラスタのリージョンを別々に設定でき、リードレプリカを複数設置することができる優れものです。
ただし、NoSQL仕様なDynamoDBのグローバルテーブルみたいに、どのレプリカでも書き込み処理ができるわけではなく、それはあくまでプライマリDBに対してだけとなります。
書き込み転送オプションとは何?
そんなAmazon Aurora Global Databaseは、昨年11月、リードレプリカしか設置できないセカンダリDBにおいて、書き込み処理をサポートするってアナウンスが出ていたではありませんか!
正確には、書き込み「転送」処理をサポートですね。(ちなみに、JINSはこれまではMySQLが多かったのですが、PostgreSQLをもっと使っていきます。)
https://aws.amazon.com/jp/about-aws/whats-new/2023/11/amazon-aurora-global-database-postgresql-forwarding/
データストアの読み取りと更新の操作を分離し、データベースのパフォーマンスやスケーラビリティのし易さを実現するCQRSパターンを考えれば、書き込みをするプライマリDBと、読み込みをするセカンダリDBのエンドポイントが分かれていも、アプリケーション側でクエリとコマンドの使い分けができればそれほど問題は無いと思っています。しかし、リージョンが別々の為、プライマリDBに書き込んだデータがセカンダリDBに反映されるまでに遅延が発生することを考慮したアプリケーション設計が必要となります。
書き込み転送オプションを使用した場合はどうなるかと言うと、本来は読み込み処理を行うリードレプリカが動いているセカンダリDBに対して書き込み処理も投げることができます。セカンダリDBは、引き続き読み込み処理のみ対応するのですが、書き込み処理のリクエストをプライマリDBに転送してくれます。そうすることにより、アプリケーション側で書き込み処理と読み込み処理をする先の場合分けをあまり考えなくて良くなります。これだけ聞くと良さそうな機能なのですが、結局のところ、セカンダリDBへのデータ反映の遅延を考慮する必要はありそうです。
評価してみた
とにもかくにも、この書き込み転送オプションがどんなものかを調べて採用できそうかを評価してみます。
調査したいこと
端的に言うと、書き込み転送機能における、読み取り性能への影響を測定します。書き込み転送オプションの有効化には、SESSION
EVENTUAL
GLOBAL
の3つあり、読み取り整合性レベルが違うので各々について調査しました。
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/aurora-global-database-write-forwarding-apg.html#aurora-global-database-write-forwarding-isolation-apg
調査方法
1. psqlにてGlobal DBのPrimaryリージョン/Writerエンドポイントへ接続する
2. fooテーブルを作成する
CREATE TABLE foo (
id numeric PRIMARY KEY
)`
3. SQL実行時間計測をONにする
`\timing`
4. INSERT文の直後にSELECTを実行し、SELECTの実行時間を確認する(書き込み:Local、読み込み:Local) ※10回繰り返し計測
`INSERT INTO foo values(1); SELECT count(*) FROM foo;`
5. テーブルをTruncate
`TRUNCATE TABLE foo;`
6. psqlにてGlobal DBのSecondaryリージョン/Readerエンドポイントへ接続する
7. 一貫性オプションを設定する
`SET apg_write_forward.consistency_mode = 'session';`
8. SQL実行時間計測をONにする
`\timing`
9. INSERT文の直後にSELECTを実行し、SELECTの実行時間を確認する(書き込み:Remote、読み込み:Local) ※10回繰り返し計測
`INSERT INTO foo values(1); SELECT count(*) FROM foo;`
10. テーブルをTruncate
`TRUNCATE TABLE foo;`
環境
- Aurora PostgreSQL 15.4
- インスタンスクラス
- db.r5.large(Global DBを利用できる中で最も安価なもの)
- インスタンス配置
- Primaryリージョン(ap-northeast-1)
- Writer ap-northeast-1a
- Reader ap-northeast-1c
- Secondaryリージョン(us-west-2)
- Reader us-west-2a
- Reader us-west-2c
- ストレージ
- Auroraスタンダード
- 接続
- RDS Proxy経由
- パブリックアクセスは無効
- us-west-2に配置したEC2からSecondary RegionのReaderに接続(Local Region内での通信となる)
調査内容のイメージ
調査結果
結論としては、書き込み転送機能を利用した場合は、書き込み転送機能を利用しない状態と比較して、読み取りと書き込み両方のクエリの処理速度が遅い傾向にありました。
当たり前ではありますが、データベースインスタンスが複数のリージョンに分散していて、読み取り整合性を高めたいのであれば、そのデータが全てのインスタンスに反映されるまでは読み取り・書き込みが制限される為だと思います。
所感
この調査は、Amazon Aurora Global Databaseの書き込み転送オプションは使いづらいと言いたいのではなく、あくまでも実現するアーキテクチャにおいて、「読み取り整合性」をどれだけ担保する必要があるのか、または結果整合性にどれだけ寄せるのかよって評価が変わるということです。また、RDS Proxyを使用している場合も考慮が必要なようでこの辺りもしっかり考えます。
JINSの場合は、グローバル全体でシステムのスケーラビリティやアベイラビリティを高める方法であったり、イベント駆動アーキテクチャや、イミュータブルデータモデルにも挑戦中なので、それらを踏まえてデータ配置をどうすると良いかを判断していきたいと思います。