概要
- Recall.aiで 大量の会議データ をPostgresに同時書き込みするユースケース
- Postgresの LISTEN/NOTIFY 機能によるスケール問題の発見
- グローバルロック によるパフォーマンス低下とダウンタイム発生
- 問題の再現と原因特定のプロセス
- 回避策 と今後の教訓
Postgres LISTEN/NOTIFYによるスケーラビリティ問題の発覚
- Recall.aiでは、 1ヶ月あたり数百万時間分の会議データ をリアルタイムでPostgresに書き込み
- データは ビデオ・音声・構造化データ(文字起こし・イベント・メタデータ) に分類
- 数万の “meeting bot” が同時にデータを書き込み
- Postgresの LISTEN/NOTIFY 機能を利用し、botの設定更新などの通知を実装
- 非常に高い同時書き込み負荷で Postgresが停止 する事象が発生
問題の発見と調査プロセス
- 2025年3月19日~22日にかけて 3回の大規模ダウンタイム を経験
- 症状:
- データベース負荷と待機セッションが 急増
- クエリスループットが激減
- CPU・ディスクI/O・ネットワークトラフィックが 著しく低下
- lock contention(ロック競合) を疑い、
log_lock_waitsを有効化して調査 - ログ解析により、 updateエンドポイント (bot設定更新時NOTIFY発行)が負荷増加と相関
ロックの詳細と根本原因
- ログに AccessExclusiveLock on object 0 of class 1262 of database 0 という異常なロックが多数記録
- Postgresのソースコード調査で、 NOTIFYを含むトランザクションのCOMMIT時 に「データベース全体のグローバルロック」を取得する仕様を確認
- このロックは 全てのCOMMITを直列化 し、 大量の同時書き込み時にボトルネック となる
- LISTEN/NOTIFYはスケーラビリティに向かない ことが判明
問題の再現と比較検証
- NOTIFY有効時:
- トランザクションコミットが直列化 され、スループットが著しく低下
- NOTIFY無効時:
- 通常通り高い並列性 で処理可能、パフォーマンス回復
回避策と教訓
- LISTEN/NOTIFYの利用を停止 し、別の通知手段(例:外部メッセージキュー)へ移行
- Postgresを 多数の同時書き込みが必要なワークロードでLISTEN/NOTIFYに依存しない 設計の重要性
- 高負荷環境でのPostgres運用時は、内部ロック機構の理解が不可欠
まとめ
- Postgresの LISTEN/NOTIFYは便利だが、グローバルロックによるスケール制約 が存在
- 大量同時書き込み環境では利用を避ける べき
- 問題発見のためには 詳細なロギングとソースコードレベルの調査 が有効
- 通知設計は外部キュー利用等で分離 し、データベース本体のスケーラビリティを守ることが推奨