GitLab.comはどうやって6TBのPostgreSQLを9.6から11にたった2時間で移行したのか?
GitレポジトリのホスティングサービスGitLab.comは2020年の5月に 6TB あるPostgreSQL 9.6クラスターをたった2時間のメンテウィンドウ中に11.7へアップグレードしました。
GitLab.comのエンジニアブログに、このPostgreSQLのメジャーアップグレードプロジェクトが解説されていたので、かんたんにご紹介します。
How we upgraded PostgreSQL at GitLab.com | GitLab
ポイント
- PostgreSQL 9.6から 11.7 へのメジャーアップグレード
- 2時間のメンテナンスウィンドウ内でアップグレード完了
- データサイズは6TB
- DBクラスターは GCP 上の 12台の VM インスタンスで構成
- クラスターはアップグレード用の8台とリカバリー用の4台に分割
- pg_upgrade & ハードリンクでインプレースアップグレード
- 入念な事前検証と手順の自動化により、当日は計画通りに遂行
PostgreSQLを9.6から11にメジャーアップグレードの背景
- PostgreSQL 9.6 は 2021年11月にEOLを迎える
- 最新の12系よりも3バージョンも古い
- GitLab 13.0 では PostgreSQL 10 系のサポートを打ち切る決断をした
- そのため、PostgreSQL 11 系にアップグレードすることにした
データベースの動作環境
- GCP の 12 台の VM インスタンス(n1-highmem-96)でクラスターを構築。マネージド・サービスではない
- データサイズは 6 TB
- PGBouncer, Patroni, Consul などで冗長構成やクエリーの分散などを行う ← これらシステムとの連携は本記事では解説せず
プロジェクトの流れ
- DBアップグレード用開発環境の構築
- ステージング環境で部分的な試験
- ステージング環境で end-to-end 試験
- 本番環境でメジャーアップグレード
このアップグレードプロジェクト向けに、次のエピックが切られています。
Upgrade Postgresql to version 11.7 on GitLab.com (&106) · Epics · GitLab Infrastructure Team
1. DBアップグレード用開発環境の構築
- ステージング環境はステージングとして残し、アップグレード用の開発環境を別途作成
- 開発環境はステージングのスナップショットから作成
- 構築手順は自動化
2. ステージング環境で部分的な試験
- ステージング環境で、リストアなど様々なステップの自動化を既存の構成管理ツールに組み込む
3. ステージング環境で end-to-end 試験
- データベースへのクエリーの停止から、クラスターの一部だけを利用したアップグレード、動作確認までの end-to-end なアップグレードをステージング環境で 実施
- 試験完了後は、リストアのシナリオを流して、ステージング環境をもとの状態に戻す。→結果的に、アップグレードのロールバックの試験になっている。
- 都合7回実施
4. 本番環境でメジャーアップグレード
- 2時間の計画メンテナンス中にメジャーアップグレード完了
- 計画どおりに進行
アップグレード一発目のスナップショットの取得に想定外の時間がかかり、玉突き事故を起こして (ry というようなこととは無縁です。
pg_upgrade でアップグレードした理由
pg_upgrade は データフォーマットをターゲットのバージョンに高速に変換するツールで、PostgreSQL に付属します。
公式ドキュメントから引用します。
Major PostgreSQL releases regularly add new features that often change the layout of the system tables, but the internal data storage format rarely changes. pg_upgrade uses this fact to perform rapid upgrades by creating new system tables and simply reusing the old user data files.
6TBのデータに対して、短いダウンタイムでアップグレードさせる必要があります。
pg_upgrade 方式は、ロールバック含めて手順が確立されており、高速に動作することから、採用されました。 データサイズが大きいため、大量の I/O が発生しないよう、コピーモードではなく、ハードリンクモードで実行します。
ダンプ・リストア方式は、ダウンタイム要件を満たせず、理論的には美しい論理レプリケーション方式(Londiste/Pglogical/Egres)は、どのツールも検証が大変なことから見送られました。
技術検証結果は次のドキュメントで確認できます。
library/database/postgres/Postgresql-upgrade/blueprint · GitLab.com / GitLab Infrastructure Team
10年も前の古い資料ではありますが、pg_upgrade 開発者がダンプ・リストアと pg_upgrade のベンチマーク結果を公開しています。
ダンプ・リストア(直列だと300分)より pg_upgrade のほうが遥かに速く、pg_upgrade でもコピーモード(44分)とリンクモード(0.7分)で処理時間が大きく異なることがわかります。
ロールバックの流れ
アップグレード失敗時のロールバックシナリオを確認します。
本件では、リンクモードの pg_upgrade というインプレースど真ん中のアップグレードを行っているため、一度アップグレードの走ったインスタンスを戻す事はできません。
そのため、12台あるインスタンス群を
- 8台のアップグレード用
- 4台のリカバリー用
の2群に分けます。
さらに、インスタンスにアタッチされたディスクのスナップショットも取得します(gcloud compute disks snapshot
)。
リカバリー時には以下の流れで対応します。
- リカバリー用インスタンス4台で 9.6 系クラスターを構成
- スナップショットからさらに4台を追加
- 動作確認後にメンテナンス終了
詳細は次のドキュメントを参照ください。
回帰テスト
データベースエンジンのアップグレードはデータの整合性を担保するだけでは不十分です。
クエリーの性能劣化も検出する必要があります。
そのため、pg_stat_statements
テーブルで SQL をキャプチャーし、 JMeter で PostgreSQL 9/11 それぞれにクラスターに対して本番に近いような負荷をかけ、パフォーマンスを計測します。
本プロジェクトでは、計測は2回に分けて実施され、特に問題のあるクエリーは見つかりませんでした。
クエリーのパフォーマンス計測は、次のイシューでまとめられています。
補足:Amazon RDS for PostgreSQL のメジャーアップグレードも pg_upgrade を利用
Amazon RDS for PostgreSQL も pg_upgrade
方式でメジャーアップグレードします。
To safely upgrade your DB instances, Amazon RDS uses the pg_upgrade utility described in the PostgreSQL documentation.
https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.PostgreSQL.html
具体的には
- スナップショットを取得
pg_upgrade
- アップグレード完了後に スナップショットを取得
という流れで行われ、リカバリーにはアップグレード前に取得したスナップショットを利用します。
詳細は次のドキュメントを参照ください。
Upgrading the PostgreSQL DB engine for Amazon RDS - Amazon Relational Database Service
最後に
サービスが続く限り、データベースのメジャーアップグレードはついて回ります。 オンプレ運用している場合も、IaaS上でデータベースを運用している場合も、マネージド・サービスでデータベースを運用している場合も同じです。
GitLab.comは6TBもあるPostgreSQLクラスターをわずか2時間のダウンタイムで9.6から11.7にアップグレードしました。
- 適切な技術選定
- 手順の自動化
- 入念な事前検証
の賜物です。
GitLab は情報公開に積極的なため、プロジェクトページからより詳細な情報にアクセスできます。ドキュメント、スクリプトはもちろんのこと、アップグレード中のコンソール画面を含めたウェブ会議の録音まで YouTube に公開されています。
データベース移行を計画的・低リスクに進められるよう、ドキュメントを漁るのも面白いと思います。
それでは。