MoTLab -GO Inc. Engineering Blog-MoTLab -GO Inc. Engineering Blog-

Aurora PostgreSQLアップグレード時のダウンタイムをBlue/Greenデプロイ方式で軽減

SRE
February 10, 2023

SREグループの古越です。

SREグループではAurora PostgreSQLのインプレースアップグレードで少し痛い目を見た過去があり、Aurora PostgreSQL 10.x EOS(2023/01/31)を切っ掛けとしてインプレースに変わる安全なアップグレード方法を模索していました。 2022/9頃から検証を始め、論理レプリケーションを使ったBlue/Greenデプロイ方式のアップグレード手順を確立することが出来ました。背景と具体的な手順について紹介していきます。


背景など

PostgreSQLは1年に1つ新しいメジャーバージョンがリリースされ、メジャーバージョンごとに初期リリースから5年でEOL(End of Life)を迎えます。

Aurora PostgreSQLは本体のPostgreSQLよりも2ヶ月程度遅れる形でEOS(End of Support)がやってきます。ユーザ目線で見ると、利用開始から5年以内に最低1回はアップグレードのアクションが必要になっています。

PostgreSQL EOLなど最新情報はこちらから確認出来ます。

https://www.postgresql.org/support/versioning/

アップグレード方式

一般的にPostgreSQLのアップグレード方式として以下の2種類が挙げられます

  • インプレースアップグレード
  • 論理レプリケーションを使った新しいクラスターへの移行 (Blue/Green方式)

インプレースアップグレードは手軽に行うことが出来ますが、長めのダウンタイムが発生します。プロダクション環境に対する適用は、作業中やアップグレード後の影響を加味する必要が有ります。

Blue/Green方式での切り替えは管理者が頑張る事で実行可能ですが、考慮ポイントが多いためインプレースほど簡単に行えないことがデメリットとしてあります。

インプレースアップグレードの注意点

インプレースアップグレードはマネジメントコンソールからポチポチで実行できる簡単さが良いところですが、プロダクション環境に適用するには注意点がいくつかあります。

主な注意点

マイナーバージョンアップとは基礎から異なるので注意が必要です

  • アップグレード中 15~30分程度何も出来ないダウンタイムが発生する
  • アップグレード直後にパフォーマンス劣化する可能性が有る
  • PostgreSQL拡張機能は個別でアップグレードする必要がある
    • バージョンアップ前後での挙動に注意
  • インプレースアップグレードは pg_upgrade拡張で実現されているが、pg_upgradeの制約によってアップグレードが失敗することもある
  • メジャーバージョンを数段飛ばす事もできるが、アップグレード可能先は制限あり
    • アップグレードパスによって異なるが、数回アップグレードが必要なこともある

AWSのナレッジセンターに、よくあるトラブルとトラブルシュート方法が記載されているため、懸念が有れば以下をチェックして頂くと良いかと思います。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/rds-postgresql-version-upgrade-issues/

パフォーマンス劣化要因

注意点としてアップグレード直後にパフォーマンス劣化する点を挙げていますが、劣化する主な原因は2つ考えられます

  • 統計情報が失われ、クエリ実行計画の効率が悪化する
  • バッファキャッシュが失われるため、初回のクエリ応答速度が遅延する

アップグレード後は統計情報が失われるため、 ANALYZE; による統計情報再構築が推奨されています。また、バッファキャッシュ対策有無で初回のクエリ応答速度が変わるため可能ならば対処しておきたいポイントです。

インプレースアップグレードを安全行う方法

上述の注意点があるため、安全を考えた場合

  • 1~2時間程度のメンテンス時間を確保
  • メンテナンス中にアップグレードを実施し、ANALYZEやバッファキャッシュ暖機を実行

という形で段取りすれば安全にアップグレードできるかと思います

Blue/Green方式のモチベーション

インプレースアップグレードでも良いのですが過去に苦い経験があり、なるべくダウンタイムが少ないBlue/Green方式を模索していました。

インプレースアップグレードの苦い経験

過去にAurora PostgreSQL 9.xのEOSを迎えるサービスがあり、10.xバージョンに引き上げる作業をSREグループで行っていました。

300GB程度のDBをメンテナンスに入れず、オンラインでインプレースアップグレードした結果

  • 20~30分程度のダウンタイム
  • 続いて1~2時間 利用が困難になる程度のパフォーマンス劣化が継続

というユーザ影響が出てしまいました。

マイクロサービスの恩恵で1DB単位の影響が小さくなっている

もう一つの背景としてはマイクロサービスの採用があります。MoTではAurora PostgreSQLを使っているマイクロサービスが多くあります。基本的にサービス毎にRDSクラスターを分離してるため、アップグレード頻度は増えてしまっています。

ただメリットもあります。モノリシックなサービスよりはDBが分散してるため、インフラ部分の瞬間的なトラブルによるユーザ影響は小さくなります。サービスの特性にもよりますが、1サービスでダウンタイム数分または数秒レベルに最小化できるなら、オンラインでDBアップグレードを行ってもユーザーが体感出来ないレベルまで影響を落とすことが可能と考えられます。

そういった経緯や背景があり

  • メンテナンス時間を確保せずダウンタイムを抑えてアップグレードしたい
  • 可能な限り最新版まで一気にアップグレードして、メンテナンス頻度を下げたい
  • 将来PostgreSQL 11以後をアップグレードするときに備え、手順を標準化したい

というモチベーションになり、DB UPgradeに合わせてBlue/Green方式を標準化しようと取り組む事になりました。2022/9頃から事前検証とアップグレード作業を積み重ねて今に至ります。

Amazon RDS Blue/Green Deployment (MySQL版のみ) について

本題から逸れますが、2022/11頃にAmazon RDS Blue/Green Deploymentがβ版として発表されています。Aurora MySQLユーザはメジャーアップグレードする方法を複数個から選択肢できるようになっています。

https://aws.amazon.com/jp/blogs/news/new-fully-managed-blue-green-deployments-in-amazon-aurora-and-amazon-rds/

実際に試したところ

  • 事前にレプリケーションを貼り、任意のタイミングで切り替える形を取る
    • 切り替え前にバッファ暖機(pre-warming)など手を加えることが出来る
  • 切り替え中 1分程度のダウンタイムが発生する
  • RDS Endpointは更新不要 Blue/Greenクラスターが切り替わる
  • Cluster IdentifierもBlue/Greenで切り替わるため、terraformなどの管理ツールと相性が良い

という点がわかっています。

意外にダウンタイムが長い印象はありますが、お手軽に実行出来る点が素晴らしいと思います。PostgreSQL版が提供されてないことが残念で、将来使えることを期待しながら本記事を書いております。

仮にPostgreSQL版がリリースされても、読み込みダウンタイムを最小化したい場合は本記事のようなアプローチが参考になるかもしれません。

Blue/Green方式 手順解説

前置きがだいぶ長くなりましたが、今回紹介するBlue/Green方式の手順について概要から説明致します。

構成踏まえた大まかなイメージとしては以下となります。

An image from Notion

Blue/Green

実環境と微細は異なりますが、AWS上でよくある構成を基にイメージして頂くための簡易な図です。自分がやったときはEC2踏み台サーバは無く、EKS上で作業用podを起動して作業しています。

大まかにはRDS Blue/Green Deploymentと似た要領で、準備と切り替えの2ステップになります。

事前準備

  1. Blueクラスターの論理デコード有効化, 再起動
  2. Aurora PostgreSQL 14.x Cluster (green)を新規作成
  3. Blue → Green で論理レプリケーションを貼る
    • スキーマ情報を同期する
    • 論理レプリケーションを貼る
  4. ANALYZE, buffercache warmupを終わらせる

(事前準備が終わった後、新しくDDLを発行しないよう関係者と調整する)

切り替え

  1. Blue側の書き込みを停止する
  2. 論理レプリケーションを停止する
  3. sequenceを Blue → Green で手動同期する
  4. アプリケーションのRDSエンドポイントを書き換える
  5. 動作確認

Blue/Green方式のダウンタイムについて

影響は以下の通りです

  • 事前準備
    • Blueクラスター再起動 20~30秒程度のダウン
  • 切り替え中
    • Read Query: ほぼゼロ (瞬断有り)
    • Write Query: 切り替え作業中の数分間

設定中のパラメータ次第ですが、レプリケーション準備に再起動が必要なケースがあるので、準備段階にダウンタイムが発生するケースが有ります。

切り替え作業は稼働している2つのDBクラスターを切り替える作業になるため、TCP的なダウンタイムは発生しません。しかし、データの整合性を担保するために書き込みクエリを一瞬停止する必要が有り、書き込みエラーが発生するタイミングが有ります。

書き込み停止~切り替えの期間はスムーズにすすめることができれば数分で完了します。

論理レプリケーションについて

MySQLの場合はバイナリログレプリケーションが知られているかと思います。MySQLバイナリログレプリケーションは1つ先のメジャーバージョンに対してレプリケーションを貼ることができるため、メジャーバージョンアップに利用できる特徴があります。

対してPostgreSQL公式のレプリケーション技術は2種類存在します

  • ストリーミングレプリケーション (旧名 物理レプリケーション)
  • 論理レプリケーション

ストリーミングレプリケーションは一般的にリードレプリカを作成するケースで利用されていてWAL(Write Ahead Log)をディスクのブロックレベルでレプリケーションしている点が特徴です。シンプルですがメジャーバージョンを跨ぐレプリケーションが出来ないため、アップグレードには使うことが出来ません。

論理レプリケーションはWALをデコード(論理デコード)したデータを基礎として、デコードしたデータを転送先でリプレイする事で実現されてます。debeziumのような論理デコードを使ったCDC(Change Data Capture)に近い方法で実現される方式でして、一つ以上先の異なるメジャーバージョン間でもレプリケーションが可能になっています。

また、共通して言える事ですがPostgreSQLの場合はWALにすべての書き込み履歴が残っているため、mysqldump & ポジション一致のような作業は必要ありません。レプリケーションを設定した段階で初めから同期されます。

私自身あまり詳しくないところからはじめましたが、レプリケーション技術については以下スライドが非常によく纏まっております。

https://www.slideshare.net/masahikosawada98/postgresql-86891271

論理レプリケーションの設定自体は簡単です。

  1. 発信側で論理デコードを有効化する (要再起動)
  2. 手動でDDLを同期する
  3. 発信側にPUBLICATION を作成する
  4. 受信側にSUBSCRIPTION を作成する

これでレプリケーションを組むことが出来ます。

論理レプリケーションの制約について

メジャーバージョンを跨ぐレプリケーションが可能だったり、特定のテーブルに限定するなど調整が可能な所が論理レプリケーションの良い点です。ただ細かい制約があるため注意が必要です。

制約

注意すべき点を抜粋すると以下になります

  • DDLがレプリケーションされない
    • pg_dump —schema-only → restoreが必要
    • Auroraの場合、最大の権限を持つマスターユーザが各roleのパスワードを出力出来ないためパスワード移行は別途対策が必要
  • シーケンスがレプリケーションされない
    • データ型に SERIAL を指定した場合のカウンターが同期されない
    • 別途同期作業が必要
  • ラージオブジェクトはレプリケーションされない
    • 別途同期作業が必要

詳しくは公式ドキュメントに記載されています。

https://www.postgresql.org/docs/current/logical-replication-restrictions.html

制約の回避策など

DDLとシーケンスがレプリケーションされない点については、アップグレード用途ならpg_dumpによる手動同期策があるのであまり問題になりません。

そしてAurora PostgreSQL限定の制限になりますが、Auroraのマスターユーザは一部権限が制限されているためpg_dumpで他のユーザ(role)のパスワードを出力することが出来ません。パスワードは別の形で再設定するなど、ひと手間必要になります。

ラージオブジェクトがレプリケーションされない点も注意が必要です。ただ、多くのケースでそこまで重用してないかと思います。利用している場合は書き込み停止時に pg_dump & restoreしてデータ移行するなど回避策を検討すると良さそうです。

詳細手順 (準備)

具体的なコマンドを交えながら紹介していきます。

1. Blueクラスターの論理デコード有効化, 再起動

論理レプリケーションするためには再起動が必要なパラメータを事前に入れる必要が有ります。

Auroraの場合はパラメータ名が少しややこしいですが

  • パラメータグループの rds.logical_replication1 に設定
  • 再起動

で論理デコードが有効化されます。

このパラメータのために再起動を調整する必要があるため、将来のアップグレードに備えてクラスター作成時に有効化しておくと良いと思います。

2. Aurora PostgreSQL 14.x Cluster (green)を新規作成

2-1. 空のクラスターを新規作成

詳細な手順は割愛しますが、snapshotからの復元等は不要で空のクラスターで構いません。

PostgreSQLはWALにすべての書き込み記録が残っているため、空状態からのフルロード、レプリケーション維持が容易に出来るようになっています。

MySQLの場合はバイナリログが時間経過で消えてしまうため、ログ記録されてないデータをdump & restoreしたり、ログの何処から読み取るかといったポジション指定作業が必要でした。作業自体はMySQLより簡単になると思います。

2-2. レプリケーション用 SecurityGroup開放

論理レプリケーションはMySQLレプリケーション同様にレプリケーション先が主体的に動いてデータを取得しに行きます。

PUBLICATION, SUBSCRIPTIONという設定が有り主体が分かりにくいのですが、PUBLICATION(Blue) <-port:5432- SUBSCRIPTION(Green) の経路で通信しています。

BlueクラスターのSecurityGroupを修正しGreenクラスターからのinbound 5432を許可してください。

2-3. その他の事前準備

踏み台サーバに相当するものがない場合、Blue, Green両方のクラスターにpsqlコマンドでログイン出来る環境を事前に作っておいてください。

作業用にEC2インスタンスを作成し、postgresをインストールするのが手っ取り早いかと思います。

3. Blue, Greenクラスターで論理レプリケーションを貼る

今回はBlue, Greenと双方のクラスターに対して入力が必要なポイントが多数あります。

細かいコマンド入力を省くため、psql, pg_dumpで共用出来る環境変数を使っていきます。

環境変数に以下の値をセットして後続作業を進めます。

# psql,pg_dump共用環境変数
export PGPORT=5432
export PGDATABASE=main
export PGUSER=postgres # Master User
export PGPASSWORD=postgres
# RDS Endpoint
export BLUE_PGHOST=<blueクラスター クラスターエンドポイント>
export GREEN_PGHOST=<greenクラスター クラスターエンドポイント>

ちなみに、パスワードを PGPASSWORD に記録して良いかは環境によって違いますので注意してください。いくつかのOSではroot以外のユーザがpsコマンド経由で環境変数を見ることができるため、セキュリティリスクが有るようです。

仮に別組織と共用してる踏み台サーバが有る場合、パスワードファイルを使う形が良さそうです。適宜使い分けていただければと思います。

3-1. スキーマ同期

pg_dump —schema-only を使うとDDLを読み取ることが出来るため、同期作業に利用します。

dump結果はそのまま実行できるSQLになっているため、Blue側のpg_dumpの出力にパイプを通しGreenクラスターに横流しすると楽に同期出来ます。

pg_dump -h "${BLUE_PGHOST}" --schema-only | psql -h "${GREEN_PGHOST}"

3-2. 論理レプリケーション設定

DDLの同期が終わったら以下のようにBlueクラスターに PUBLICATIONを作成します。

名前は任意で良いのですが、 今回は engine_upgrade という名前で作成します。

psql -h "${BLUE_PGHOST}" -c "CREATE PUBLICATION engine_upgrade FOR ALL TABLES;"

続いてGreenクラスターにもSUBSCRIPTIONを設定します。こちらも任意の名前で良いです。

上記で設定したengine_upgrade というPUBLICATIONを見に行くように設定します。

psql -h "${GREEN_PGHOST}" -c "CREATE SUBSCRIPTION engine_upgrade CONNECTION 'host=${BLUE_PGHOST} port=${PGPORT} dbname=${PGDATABASE} user=${PGUSER} password=${PGPASSWORD}' PUBLICATION engine_upgrade;"

問題なければ、このSUBSCRIPTIONを設定した直後からレプリケーションが開始します。

今回はアップグレード用の一時的なレプリケーションを目的としているのでRDSのマスターユーザをそのまま使う手順としています。セキュリティが気になる場合はレプリケーション用ユーザを別途発行する形が良いと思います。

3-3. レプリケーション状態の確認

レプリケーション開始後は以下のコマンドを見て状況を確認出来ます

PUBLICATION

psql -h "${BLUE_PGHOST}" -x -c "\\dRp"
psql -h "${BLUE_PGHOST}" -x -c "SELECT * FROM pg_stat_replication;"

pg_stat_replicationは送る側の統計情報を見れますが、レプリケーションがうまくいっているか判断するには十分な情報が有りません。軽く目を通して問題無さそうか見る程度で良いです。

SUBSCRIPTION

psql -h "${GREEN_PGHOST}" -x -c "\\dRs"
psql -h "${GREEN_PGHOST}" -x -c "SELECT * FROM pg_stat_subscription;"

後述しますが、SUBSCRIPTION側の情報には幾つか重要な情報が有ります。

なおPostgreSQL 15からは pg_stat_subscription_stats という良いビューが存在しますが、PostgreSQL 10.x~14.xには存在しないため今回は省略します。

DBサイズの確認

psql -h "${BLUE_PGHOST}" -x -c "SELECT pg_size_pretty(pg_database_size(current_database()));"
psql -h "${GREEN_PGHOST}" -x -c "SELECT pg_size_pretty(pg_database_size(current_database()));"

レプリケーションが始まるとGreen側のpg_size_prettyが大きく変動していきます。

Blue側とGreen側のサイズを比較して、レプリケーション進捗を確認出来るので、両方同時に出力して様子を観察すると良いでしょう。

実際にやってて気づいた所ですがDBエンジンの更新に伴ってデータの圧縮効率は変わっているようです。PostgreSQL 10.x, 14.x それぞれレコード数が同じでもGreen側が概ね 10%程度小さくなる傾向が有りました。

確認方法は以上の通りですが、レプリケーションを貼った後に以下観点で問題無いこと確認すると大変良いと思います。

初期ロード中の確認ポイント

Green側のpg_stat_subscriptionを繰り返し実行し、以下をチェックする

  1. 各lsnの値に動きがあり、レプリケーションが維持されていること
  2. received_lsn, latest_end_lsn が近い値になっていること (8桁の16進数)
  3. last_msg_send_time, latest_end_timeが近似していること

その後の確認ポイント

  1. Green側のpg_stat_subscriptionを確認 latest_end_time が現在時刻に近い値であること
  2. AWSコンソールから error/postgresql.log を確認。エラーが無いこと
  3. pg_sizeに大きな差が無いこと (10%程度誤差あり)

すべて問題なければレプリケーションは完了です。

補足: 初回ロードからレプリケーションラグ解消までの所要時間

一概には言えませんが参考情報として、以下の条件では約5,6時間かかりました。

  • pg_size_pretty: 400GB程度
  • Blue, Green RDS Instance Type: db.r6g.2xlarge

レプリケーション速度はデータ構造やインスタンスタイプによって異なると思いますが、データ量が多い場合は早めにレプリケーションを貼るように日程調整が必要そうです。この点はご注意ください。

4. ANALYZE, buffer warmupを実行する

レプリケーションが追いついた後、切り替わり直後のパフォーマンス劣化を防ぐために統計情報の更新とバッファの暖機を行います。

4-1. ANALYZE

ANALYZEは1クエリ実行すれば完了します。

psql -h "${GREEN_PGHOST}" -c "ANALYZE;"

注意点ですがDBサイズ次第で時間がかかることを加味して、事前に実行することをオススメします。400GBのクラスターの場合は15分程度かかりました。

4-2. buffercache warm up

pg_buffercacheとpg_prewarmという拡張を使う事で bufferを暖機することが出来るので使い方を説明してきます。

まずはBlue側でpg_buffercacheを有効化し、よくbufferを利用しているテーブルを表示して調査します。

psql -h "${BLUE_PGHOST}"
-- pg_buffercache 有効化
CREATE EXTENSION pg_buffercache;

-- バッファページ数集計 (pg_* 系は除外)
SELECT c.relname, COUNT(*) AS buffers
FROM
    pg_buffercache b
    INNER JOIN
        pg_class c
    ON  b.relfilenode = pg_relation_filenode(c.oid)
    AND b.reldatabase IN(0,(
                SELECT oid
                FROM pg_database
                WHERE datname = current_database()
            ))
WHERE c.relname NOT LIKE 'pg_%'
GROUP BY c.relname
ORDER BY 2 DESC
LIMIT 20;

上記SQLで TOP 20のテーブルをざっと確認します。

次にGreen側でpg_prewarmを使ってバッファを温めます。

psql -h ${GREEN_PGHOST}
-- pg_prewarm 有効化
CREATE EXTENSION pg_prewarm;

-- buffercacheの集計クエリを元に pg_prewarmでテーブルを指定して暖機する
-- 注意: bufferが蓄積した時は古いbufferから消えるため、利用頻度の低いテーブルから順に実行する
SELECT pg_prewarm('table5');
SELECT pg_prewarm('table4');
SELECT pg_prewarm('table3');
SELECT pg_prewarm('table2');
SELECT pg_prewarm('table1');

bufferは共有メモリですのでbufferに載せられるデータは限界が有ります。

bufferが十分に蓄積したときは古いbufferから消えていくため、利用頻度の低いテーブルから順に実行する事で、よく使うテーブルを優先的に暖機出来ます。

厳密にはもっと最適な暖機方法が有るかと思いますが、このアプローチでも一定の効果が見込めると思います。暖機した後、Green側にもbuffercacheの調査クエリを投げ Blue側と似たような状態か確認すると良いでしょう。

切り替え前の準備は以上です。

詳細手順 (切り替え)

以後の作業はエンドユーザー影響が発生するため、なるべく利用者の少ないタイミングで実施するかメンテナンスを調整して実施する事をオススメします。

1. Blue側の書き込みを停止する

データベース全体に対して default_transaction_read_only = onを指定する事で書き込みを停止出来ます。

しかし、このパラメータが効くのは新規コネクションからです。コネクションプーリングしているようなケースの既存コネクションには影響しません。

100%書き込みを停止させるために、既存のコネクションを一度遮断すると良いと思います。

# read_onlyモード切り替え
psql -h "${BLUE_PGHOST}" -c "ALTER DATABASE ${PGDATABASE} set default_transaction_read_only = on;"

# rdsadminユーザ、replicationプロセスを除外したpidを遮断する
psql -h "${BLUE_PGHOST}" -x -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = current_database() AND pid <> pg_backend_pid() AND usename <> 'rdsadmin' AND application_name <> 'engine_upgrade';"

default_transaction_read_onlyはパラメータグループにも項目があります。ただ、こちらで検証したときはパラメータグループを変更しても書き込みを止めることが出来ませんでした。

ALTER DATABASEクエリで実行する方法が高速で確実かと思います。

書き込み停止の確認方法

書き込みが本当に停止しているか確認するにはpg_stat_activityを見るだけでは判断出来ません。pg_stat_databaseビューをwatchコマンドなどで目視して書き込み停止を確認する事をオススメします。

watch -n 0.5 "psql -x -c 'SELECT datname,xact_commit,xact_rollback,tup_inserted,tup_updated,tup_deleted,conflicts FROM pg_stat_database WHERE datname = \'${PGDATABASE}\';'"

対象データベースの tup_inserted, tup_updated, tup_deletedのカウンターが止まっていれば書き込みは停止しています。

補足: 書き込み停止の必要性

書き込みの静止点を必ず確保し、十分確認することを強くオススメします。

ダウンタイムを少なくしようと焦ると、書き込み停止確認を怠ってしまう事があります。必ず確認してください。30秒から1分程度様子を見る形でも良いと思います。

万が一パラメータにミスが有ってBlue側に書き込みが継続していた場合、Greenに切り替えた後にデータが欠落してしまいます。データ欠落を実際にやらかした事があるのですが、欠落したレコードの洗い出しと復元を迅速に行う事が求められ、レプリケーション作業より難易度の高いオペレーションが必要になりました。

深刻な被害を出さないために、小さなエラーを許容するというマインドでよいかと思います。

2. 論理レプリケーションを停止する

書き込みが停止している場合はレプリケーションする必要も無いため、ここで停止します。

psql -h "${GREEN_PGHOST}" -c "ALTER SUBSCRIPTION engine_upgrade DISABLE;"

3. sequenceを Blue → Green で手動同期する

sequenceはDDL同様にpg_dumpで簡単に同期出来ます。

pg_dump -h "${BLUE_PGHOST}" --data-only -t '*.*_seq' | psql -h "${GREEN_PGHOST}"

このsequence同期作業は論理レプリケーションの挙動に影響ありません。

書き込みを停止する前に事前実行し、問題なく同期されるか確認すると良いと思います。

4. アプリケーションのRDSエンドポイントを書き換える

アプリケーションによって異なりますが、幾つかの方法で実現可能です。

デプロイや再起動時にダウンタイムが発生しない作りが前提になりますが、以下いずれかで実現できるかと思います。

  • 方法1: アプリケーションのパラメータ更新
    • 環境変数やconfigファイル, secret managerなどにRDSの接続情報を格納
    • パラメータを更新してアプリケーション再起動
  • 方法2: DNS Aliasの切り替え
    • Cluster, Reader Endpointと別のDNS Aliasレコードを事前に作る
    • アプリケーションにはAliasを参照するよう設定する
    • 任意のタイミングでAliasの宛先を切り替える
  • 方法3: ソースコードを直接変更して再デプロイ
  • 方法4: RDS Cluster IdentifierをBlue/Greenで切り替える (ダウンタイム有り)

MoTの多くのマイクロサービスではkubernetes secretsに格納したエンドポイントをpodの環境変数に設定しているため、方法1のパラメータ更新で切り替えています。

方法4のCluster Identifier切り替え方式はMySQL版 RDS Blue/Green Deploymentが採用している方法と同じです。アプリケーション側の対応が不要になりますが、他方法と比べるとTCP的なダウンタイムが発生する点がデメリットとしてあります。

アプリケーションに手を入れることが出来ないときの最終手段として使えば良さそうです。

5. 動作確認

アプリケーション自体を動作確認するのが手っ取り早いですが、DBも含めて全体的に確認しておきましょう。

チェックするポイントとしては以下の通りです

  • RDS 切り替わり確認
    • RDSメトリクスから確認
      • Blue側のコネクションが0になること
      • 切り替え後にGreen側のコネクションが増えている事
      • 書き込みレイテンシー、読み込みレイテンシーがBlue, Greenで大きな違いが無い事
    • Blue/Green それぞれ pg_stat_activityを確認 意図しない接続が無いことを確認
  • アプリケーション影響
    • レスポンスタイムが悪化してないことを確認
    • 書き込み停止~切り替えタイミング以外でエラーが発生してないこと、エラーが継続してない事を確認

後片付け

論理レプリケーションの解除

psql -h "${GREEN_PGHOST}" -c "DROP SUBSCRIPTION engine_upgrade;"

SUBSCRIPTION設定を残したままPUBLICATION側のクラスターを削除してしまうと、DROP SUBSCRIPTIONがエラーになり、ひと手間必要になります。

先に解除しておきましょう。

Blue側クラスターの撤去

Greenに切り替わった後、半日程度経過を見てから撤去すると良いかと思います。

snapshotを保持して削除しましょう。

まとめ

長くなりましたがBlue/Geen方式に関してのまとめになります。

  • 論理レプリケーションでメジャーバージョンを数段飛ばしてアップグレードすることが可能
  • ダウンタイムは数分程度に抑えることが可能
    • Read Query: ほぼゼロ (瞬断有り)
    • Write Query: 数分間エラーになる
    • 準備段階で再起動が必要なケースもある (+20~30秒ダウン)
  • PostgreSQL 11.x以後でも同じアプローチが取れる
  • ダウンタイムは抑えることができるが、それなりの手間と習熟が必要
    • アプリケーション次第だが、1~2時間程度のメンテナンス時間を確保出来るならインプレースアップグレードが無難

終わりに

MoT SREグループでは今回紹介した手順を元にして、5つのマイクロサービスのAurora PostgreSQLをアップグレードしています。来年頭にAurora PostgreSQL 11.x EOSが予告されているため今年後半に再び同じアプローチで実施する予定です。

PostgreSQLはMySQLと比較すると互換性の無い変更点が少ないため、1バージョンずつアップグードせずにEOL, EOSのタイミングで一気に最新にアップグレードする戦略も可能です。今年中にはPostgreSQL 11.x → 15.xのアップグレードを段取りしていきたいと考えています。

ブログ中では割愛していますがアップグレード後にPostgreSQL ExtentionやSQLクエリが問題なく応答されるかは別途事前検証されることをおすすめします。

手動Blue/Green方式は手間と習熟が必要です。この記事が不要になるAurora PostgreSQL版 Blue/Green Deploymentがリリースされることを待ち望んでいます。


We're Hiring!

📢
Mobility Technologies ではともに働くエンジニアを募集しています。

興味のある方は 採用ページ も見ていただけると嬉しいです。

Twitter @goinc_techtalk のフォローもよろしくお願いします!