Notion
Notion、単一Postgresが限界に達し480の論理シャードへ水平分割
ユーザー急増でモノリシックなPostgresがスケール限界に近づいたNotionが、ワークスペースIDを軸に32物理DB×15論理シャード=480シャードへ分割移行した。
課題
5年で4桁成長しVACUUM停滞やTXIDラップアラウンドのリスクでCPUスパイクが頻発
アプローチ
ワークスペースID単位で480論理シャード×32物理DBへ、監査ログ方式のダブルライトで移行
効果
m5.24xlargeで3日かけて移行、ダウンタイムは5分の計画メンテナンスのみ
背景
Notionは5年間で4桁の成長を遂げる中で、単一のPostgreSQLモノリスがパフォーマンス限界に近づいていることに気づいた。不要な行(デッドタプル)からのディスク領域回収ができないVACUUM処理の停滞が最も深刻な課題で、Postgresがすべての書き込みを停止する安全機構であるトランザクションIDラップアラウンドが発動するリスクも抱えていた。オンコール担当者はデータベースのCPUスパイクで定期的に起こされ、単純なスキーマ変更さえも不安全で不確実な状態になっていた。
移行のプロセス
エンジニアリングチームはワークスペースID(UUID)をパーティションキーとして、鍵となるテーブルを整理し、各ワークスペースが特定のシャードに属するよう設計した。最終的に32の物理データベースに15論理シャードずつ、合計480の論理シャードに分割する構成とした。480という数は32から40、48ホストへと将来段階的にスケールする際に柔軟に対応できるよう、多くの数で割り切れる値として選ばれた。
移行の実行では、複数の手法を組み合わせた。
- 初期スナップショット段階でblockテーブルの書き込みボリュームに論理レプリケーションが対応できなかったため、監査ログテーブルで全書き込みを追跡しキャッチアップスクリプトが新データベースに適用するダブルライト方式を採用した
- バックフィルにはm5.24xlargeインスタンス(96 vCPU)をフル活用し約3日間で本番データを移行した
- 切り替え前には新旧両データベースを読み比べる「ダークリード」や、UUID空間の連続範囲を検証する専用スクリプトで整合性を確認した
- 移行ロジックと検証ロジックは同じミスを防ぐためあえて別の担当者が実装した
移行前後の変化
| 指標 | Before | After | |
|---|---|---|---|
| 論理シャード数 | 1(モノリス) | 480 | |
| 計画停止時間 | - | 5分間 |
結果
移行の結果は以下の通り。
- 最終的に32の物理データベース、480の論理シャードという構成に分割した
- 本番切り替えのダウンタイムは5分間の計画メンテナンスのみに抑えられた
- 移行前は最低60K IOPSが必要とされる需要があったが、各物理DBには500GB/テーブル、10TB/物理データベースという容量上限を設定した
学び
振り返りとして3点を挙げている。1つ目はシャーディングの着手をもっと早めるべきだったこと、事前にworkspace_id列をバックフィルしておけば論理レプリケーションが使えた可能性がある。2つ目はキャッチアップスクリプトの最適化にもう1週間投資すれば30秒未満のホットスワップも可能だった可能性。3つ目はidとspace_idの2カラムでなく単一の複合主キーを採用していれば、アプリケーション全体でのspace_ids通知が不要になったとしている。
