停止時間ゼロのデータベース・アップグレード:ブルーグリーンデプロイメントによるサバイバルガイド

Database tutorial - IT technology blog
Database tutorial - IT technology blog

午前2時のメンテナンス時間の悪夢

私が初めて経験した大規模なデータベース・アップグレードのことは今でも覚えています。当時、約1.2TBのPostgreSQL 9.6の本番インスタンスをバージョン11に移行する必要がありました。私の戦略は、古典的な「メンテナンス時間」を設けることでした。サイトにバナーを掲出し、深夜0時にアプリケーションの接続を遮断し、pg_dumpを開始しました。午前4時15分になってもリストアは遅々として進まず、ビジネスは収益を失い続け、私の心臓は耳元で激しく鼓動していました。

「メンテナンス時間」という概念は消えつつあります。99.999%の可用性が基準となる現代において、世界中のユーザーベースに対して「サービスが4時間停止します」と告げるのは、非常に難しい提案です。ユーザーはストレージ形式の変更など気にしません。彼らが求めているのは自分たちのデータだけです。停止時間ゼロのアップグレードは、もはや贅沢品ではなく、現代のエンジニアリングチームにとって必須の要件となっています。

なぜデータベースのアップグレードには通常停止時間が必要なのか?

ボトルネックは技術的なものです。PostgreSQLやMySQLを含むほとんどのデータベースエンジンは、メジャーバージョン間で内部のディスク形式を変更します。PostgreSQL 12で書き込まれたデータファイルは、PostgreSQL 15にとっては意味不明なものになる可能性があります。

標準的なパスを選択すると、通常は以下のいずれかを強いられます:

  • バイナリアップグレード: pg_upgradeのようなツールは高速ですが、データの整合性を確保するために依然として完全なサービス停止が必要です。
  • ダンプとリストア: すべてをSQLファイルにエクスポートして再インポートする方法です。500GBのデータベースの場合、これだけで簡単に6時間のメンテナンス時間を使い果たしてしまいます。

停止時間が発生するのは、歴史的にデータ移行とサービスの可用性を結びつけて考えてきたからです。プライマリ・データベースがデータの再構築に追われている間は、データの破損のリスクなしに新しい書き込みを安全に処理することはできません。

アップグレード戦略の比較

私は通常、ビジネスが許容できるリスクの大きさに応じて、次の3つの方法を検討します:

1. 「ビッグバン」(インプレース・アップグレード)

アプリをシャットダウンし、アップグレードツールを実行して、うまくいくことを祈ります。シンプルですが非常にリスクが高い方法です。途中でトラブルが発生すれば、バックアップからの長いリストア作業を強いられ、結果として停止時間が倍増することになります。

2. 読み取り専用移行

アプリを読み取り専用モードにロックし、データを新しいバージョンにクローンしてから切り替えます。データ損失は防げますが、作業内容の保存や購入を完了しようとしているユーザーの体験を著しく損ないます。

3. ブルーグリーンデプロイメント

これは業界で推奨されているパターンです。現在稼働中の「ブルー」(現在の本番バージョン)と、新しいバージョンの「グリーン」という2つの同一環境を並行して実行します。両者の間でリアルタイムにデータを同期し、グリーンの準備が整ったらスイッチを切り替えます。総停止時間は? プロキシやDNSレコードを更新するのに必要な、通常30秒未満です。

ブループリント:論理レプリケーションによる停止時間ゼロの実現

ストレスのないアップグレードの秘訣は、論理レプリケーション(Logical Replication)です。物理レプリケーションが生のデータブロックをコピーし、同一のバージョンを必要とするのに対し、論理レプリケーションは内容に基づいて特定のデータの変更(INSERTやUPDATEなど)をストリームします。これにより、バージョン13のデータベースがバージョン16のデータベースと問題なく通信できるようになります。

ステップ1:グリーン環境の立ち上げ

まず、ターゲットとなるバージョンの新しいインスタンスをプロビジョニングします。このインスタンスには本番環境と同じスキーマが必要ですが、最初は空の状態で開始します。プロのヒント:初期同期中は、重い制約、外部キー、トリガーを無効にしておきましょう。移行を高速化するために、これらは後で再度有効にすることができます。

ステップ2:初期データのシード

開始するには、ある特定の時点のスナップショットが必要です。私は通常、ブルー環境がライブトラフィックを処理し続けている間も一貫したスナップショットを提供できるバックアップツールを使用します。これらの移行中、小さなデータセットや設定ファイルをマップする必要がしばしばあります。データインポートのためにCSVをJSONに素早く変換する必要があるときは、toolcraft.app/ja/tools/data/csv-to-jsonを使用しています。ブラウザ上で完全に動作するため、機密データがマシン外に出ることがなく、セキュリティ面でも優れています。

ステップ3:差分同期(Delta Sync)の確立

グリーン環境にベースラインデータが揃ったら、シード作成中に発生した変更を追いつかせるための「差分」同期を開始します。PostgreSQLでは、ブルーにPUBLICATIONを作成し、グリーンにSUBSCRIPTIONを作成することを意味します。

-- ブルー環境 (PostgreSQL 12)にて実行
CREATE PUBLICATION upgrade_pub FOR ALL TABLES;

-- グリーン環境 (PostgreSQL 15)にて実行
CREATE SUBSCRIPTION upgrade_sub 
CONNECTION 'host=blue-db user=repl_user password=secret dbname=mydb' 
PUBLICATION upgrade_pub;

MySQLの場合は、行ベース・レプリケーション(RBR)を使用します。CHANGE MASTER TOコマンドを使用してグリーンをブルーのレプリカとして設定し、衝突を避けるためにserver-idが一意であることを確認してください。

ステップ4:切り替え(カットオーバー)

レプリケーションの遅延が100ミリ秒を下回ったら、準備完了です。以下の手順を厳格に守ってください:

  1. アプリケーションを一時停止するか、短いメンテナンスページにリダイレクトします。
  2. 最後の数件のトランザクションがグリーン環境に反映されるのを待ちます(遅延メトリクスを注視してください!)。
  3. シーケンス(Postgres)または自動インクリメント値(MySQL)を更新します。
  4. アプリケーションの接続文字列をグリーン環境のデータベースに変更します。
  5. アプリケーションをオンラインに戻します。

現場で培った教訓

技術的な同期は通常、簡単な部分です。事態を悪化させるのはエッジケースです。それらを先回りして回避する方法を以下に示します:

シーケンスに注意

PostgreSQLの論理レプリケーションは、シーケンスを同期しません。シーケンスを更新せずにグリーン環境に切り替えると、最初の新しいレコード作成時に主キー制約違反でクラッシュします。必ずsetval()を実行してシーケンスを更新するスクリプトを実行してください。私は安全のために、最大値に+1,000のバッファを追加するようにしています。

プロキシを活用するメリット

DNSの更新に頼ってはいけません。ブラウザによって数分間キャッシュされる可能性があるからです。PgBouncerやHAProxyのようなデータベースプロキシを使用してください。プロキシの設定をリロードして新しいIPを即座に指すように変更できます。既存の接続が一瞬停止するかもしれませんが、切断されることはありません。

スキーマの整合性

両方の環境が全く同じスキーマを持っている必要があります。グリーン環境のスナップショットを取得した後に、開発者がブルー環境にカラムを追加したことで移行が失敗するケースを見てきました。ドリフトを防ぐために、アップグレード期間中はスキーマ変更をロックしてください。

最後に

「一か八か」のアップグレードから脱却したことで、エンジニアとしての私の人生は変わりました。ブルーグリーンデプロイメントは単に稼働率のためだけではなく、安全性のためのものです。切り替え後にグリーン環境でCPUスパイクやクエリの遅延が発生しても、ブルー環境はまだそこにあり、完全に同期されており、いつでもフォールバック可能です。このレベルのコントロール性は、事前の準備に費やす時間の価値が十分にあります。

Share: