概要
Postgresの拡張機能pg_searchで書き込み性能向上のためLSMツリーを導入したが、物理レプリケーションが破損する問題が発生。 LSMツリーの特性とPostgresのWALによる一貫性確保の仕組みを解説。 物理・論理一貫性の違いと、VACUUMや圧縮処理での課題を説明。 hot_standby_feedback設定により論理一貫性を守る方法を提案。 最終的に、高速な書き込みと一貫性を両立する設計に到達。
Postgres書き込み高速化とレプリケーション破損
- pg_search はElasticsearch代替を目指すPostgres拡張機能
- リアルタイム分析や検索 用途で高い書き込み性能が必須
- 標準のB-treeやGINインデックスは 書き込みが遅い 欠点
- Log-Structured Merge(LSM)ツリー を採用し書き込み最適化
- LSMツリー導入で 物理レプリケーションが破損 する問題発生
LSMツリーとは
- LSMツリー はRocksDBやCassandraで利用される 書き込み最適化データ構造
- 書き込みはまず メモリ上のmemtable に格納
- memtableが満杯になると SSTable としてディスクにフラッシュ
- 複数のSSTableをレイヤー化し、 コンパクション で統合・重複排除
- 高頻度な書き込み・圧縮処理が特徴
レプリケーション・セーフティとは
- 分散データストアには 物理一貫性 と 論理一貫性 の両方が必要
- 物理一貫性:レプリカのデータ構造が正しい状態
- 論理一貫性:トランザクションとして一貫したデータビュー
- 物理一貫性のみでは 途中状態のデータ が生じるリスク
- 例:本の複写で途中の章をコピーするイメージ
WALによる物理一貫性保証
- Write-Ahead Log(WAL) で全てのバイナリ変更を記録
- WALを スタンバイサーバー にストリーミングし順次適用
- hot standby 構成でリアルタイム同期を実現
原子性と物理一貫性
- Postgresのロック はレプリカで再現されない
- WALはバッファ単位でロック・変更・解放を行う
- 複数バッファにまたがるデータ構造は 原子操作が必須
- pg_search はリストの複数ノード編集時に Copy-on-Write + ヘッドの原子スワップ で対処
VACUUMと論理一貫性の破壊
- VACUUMは 不要なタプル(行)を削除 するメンテナンス処理
- MVCC により複数バージョンのタプルが共存
- スタンバイでクエリ実行中にVACUUMが適用されると 途中でデータ消失 のリスク
- 長時間クエリがVACUUM済みタプルへアクセスすると クエリエラー
LSMツリーにおける脆弱性
- LSMツリーでは コンパクション頻度が高く、VACUUM同様の問題が頻発
- 高書き込み負荷 環境で衝突リスクが増大
- コンパクションやVACUUMが 安全に古いデータを削除 できるタイミングの把握が難しい
hot_standby_feedbackによる論理一貫性確保
- hot_standby_feedback 設定でスタンバイからプライマリへ 安全な削除範囲 を通知
- 各タプルの xmin(生成XID) と xmax(削除XID) が管理される
- スタンバイで最も古いxminをプライマリに伝え、 まだ必要なタプルの削除を防止
- VACUUMやコンパクションの安全な実行タイミング 判定が可能に
まとめと今後
- hot_standby_feedback で論理一貫性を確保しつつ、高速なLSMツリーを実現
- 物理・論理一貫性の両立 は分散Postgresでの大きな課題
- pg_search は原子ログ+hot_standby_feedbackでこの課題を克服
- 高速検索と一貫性維持 を両立した設計が可能に
- 詳細は 公式ドキュメントやオープンソースプロジェクト を参照