こんにちは、エムスリー 製薬企業向けプラットフォームチームでチームSREをやっている後藤です。
先日、担当しているサービスにてAmazon Aurora PostgreSQL を10から13にメジャーバージョンアップしました。
チームとして初めて論理レプリケーションを使ったバージョンアップを実施したので、その手順をご紹介しようと思います。
Aurora PostgreSQLのバージョンアップ
まずAurora PostgreSQLのバージョンアップについて、どのような方法が考えられるか調査しました。 AWSのドキュメント(例えばこちらとか)を参照し、大きくは下記の4つの方法があることがわかりました。
- Auroraのインスタンスはそのままにバージョンアップをする(インプレースアップグレード)
- 新規インスタンスを作成してpg_dump等でデータコピーをする
- 新規インスタンスを作成して論理レプリケーションでデータをコピーする
- 新規インスタンスを作成してAWS Database Migration Service (DMS) を使用してデータをコピーする
我々の要件から検討したところ、1の方法は10から13へのバージョンアップには使用できないため、2の方法はDBの停止時間が長くなると思われたため、採用しませんでした。
残った3と4はデータをどうやって同期するかの差ですが、DMSを使う必要性も特になかったため、PostgreSQLネイティブの機能である論理レプリケーションを使う方がシンプルであると考え、3の方式を採用しました。
3の方式を簡単に図にすると以下のようになります。
論理レプリケーションとは
論理レプリケーションはPostgreSQL 10で導入された機能です。
その大きな特徴はバージョンが異なるDB間でもデータのレプリケーションができることです。
バイナリレベルでの変更を転送する物理レプリケーション(ストリーミングレプリケーション)と比べて、論理レプリケーションではデータに対する論理的な操作を転送するため、異なるバージョン間でもデータのレプリケーションが可能となります。
論理レプリケーションにはいくつか制限事項もあります。
公式ドキュメントを参考に、論理レプリケーションが自身の要件にあっているか確認してください。
論理レプリケーション構成の構築
実際にAurora PostgreSQLの環境で論理レプリケーション構成した手順は以下の通りです。
- REPLICA IDENTITY の確認
- 新バージョンのAuroraクラスタ構築
- セキュリティグループの設定
- レプリケーション用のパラメータ変更
- レプリケーションの開始
以下では個別の手順について詳しくみていきます。
1. REPLICA IDENTITY の確認
更新や削除の操作を同期する際に、どのレコードに対する操作なのか特定するためにREPLICA IDENTITYが使用されます。
テーブルに主キーがあれば自動的に主キーが使われますが、主キーがない場合はREPLICA IDENTITYを明示的に設定する必要があります。
REPLICA IDENTITYにはユニークインデックス使うか、全ての列(full)を使うか、どちらかとなります。
REPLICA IDENTITYはALTER TABLE文で設定します。
ALTER TABLE table_name REPLICA IDENTITY { USING INDEX index_name | FULL }
2. 新バージョンのAuroraクラスタ構築
Aurora PostgreSQL 13のクラスタを新規に構築します。
パラメータなどの設定は既存のDBを踏襲しました。
その後、データベースやユーザ、ロールなど必要なものを作成した上で、スキーマの初期化を行います。
論理レプリケーションの制限事項にある通りスキーマやDDLはレプリケーションされません。
pg_dump --schema-only
を使用して既存のDBからスキーマ情報を取得して新しいDBにリストアします。
3. セキュリティグループの設定
DBへのアクセス制限にセキュリティグループを使用している場合は、既存のDBと新しいDBの間でレプリケーションの通信が可能となるように設定を確認します。
4. レプリケーション用のパラメータ変更
既存のDBにて、rds.logical_replicationというパラメータを1に変更し、論理レプリケーションを有効化します。
このパラメータの反映にはDBの再起動が必要です。
このパラメータを変更するとパフォーマンスに影響があるとされており注意が必要です。
今回我々のケースでは目立ったパフォーマンスの影響は見られませんでした。
5. レプリケーションの開始
レプリケーションを開始するには、既存DBにpublication、新しいDBにsubscriptionをそれぞれ作成する必要があります。
・publicationの作成 (全テーブルを対象とする場合)
CREATE PUBLICATION publication_name FOR ALL TABLES;
・subsctiptionの作成
CREATE SUBSCRIPTION subscrption_name CONNECTION 'host={既存DBのホスト} port={既存DBのポート} user={既存DBのユーザ名} password={userに指定したユーザのパスワード} dbname={既存DBのデータベース名}' PUBLICATION publication_name;
publicationとsubscriptionを作成すると、すでにあるデータの初期コピーが開始されます。
初期コピーは、80GBほどのデータベースで1時間半ぐらいの時間がかかりましたが、publication側のDBの負荷は小さかったので影響はありませんでした。
初期コピーが完了するとデータのレプリケーションが開始されます。
新DBへの切り替え
論理レプリケーションにて問題なくデータが同期されるようになったら、使用しているDBを新しいものに切り替えます。
今回は論理レプリケーションを設定した数日後に切り替え作業を実施しましたが、レプリケーションの初期コピーが完了してデータが同期されていれば問題ないので、早ければ数時間後には切り替え可能です。
ただし、レプリケーションでのトラブルやデータ同期の確認、作業バッファなど考えると1日程度はあける方がお勧めです。
新DBへの切り替えは以下のような手順で進めます。
- アプリケーションの停止
- DBデータの一致確認
- シーケンス値の設定
- アプリケーションの起動
1. アプリケーションの停止
DBにデータを書き込むアプリケーションを全て停止します。
これにより新規のデータ更新を全てストップします。
2. DBデータの一致確認
既存のDBと新しいDBで、レプリケーションが完了してデータが一致していることを確認します。
今回は、全てのテーブルにてレコード数が一致することの確認と、更新頻度が高いいくつかのテーブルにて最新のレコードが一致していることを確認しました。
実際に確認してみると、レプリケーションのラグはほとんどなく、ほぼリアルタイムでデータが同期されていました。
DBのデータ一致が確認できたらsubscriptionをdisableにしてレプリケーションを停止します。
ALTER SUBSCRIPTION subscrption_name DISABLE;
3. シーケンス値の設定
論理レプリケーションではシーケンス値は同期されません。
そのため、現在のレコードの最大値にシーケンス値を設定します。
SELECT setval('seq_name', (select max(seq_column_name) from table_name));
4. アプリケーションの起動
以上で新しいDBの準備が完了となるので、新しいDBに接続されるように設定を変更してアプリケーションを起動します。
バージョンアップの結果
これまでにご紹介した手順でDBのバージョンアップを進め、特にトラブルなく無事に完了することができました。
停止時間を短くすることを狙って論理レプリケーションの方式を採用しましたが、実際アプリケーションを停止してから再起動するまでの作業は20分程度で完了できました。
実際に比較はしてませんが、今回は対象のDBのサイズが約80GBと大きめだったこともあり、dump/restore方式より短い時間で作業ができたのではないかと思います。
まとめ
論理レプリケーションを活用したAurora PostgreSQLのメジャーバージョンアップの方法を紹介しました。
今回の移行方式はチームで初めてのやり方だったのもあり、事前準備や動作検証は慎重に進めました。
この記事でノウハウは紹介できたと思うので、これから取り組まれる方の参考になれば幸いです。
We are Hiring!
エムスリーではSREを募集中です。
私のチームのサービスも多くがクラウド上で稼働しており、クラウド環境の構築・保守やシステムモニタリング、デプロイパイプラインの改善などなど一緒に取り組んでいける方のご応募お待ちしています。