概要
Wayfairのプロジェクトで、Kafkaイベントストリームを用いた日次ビジネスレポート生成システムの失敗時対応を担当。 KafkaのDLQでは可観測性が低く、CloudSQL PostgreSQLをDead Letter Queueとして運用。 失敗イベント管理、再試行、監査性向上のためのDLQテーブル設計とインデックス戦略。 ShedLockによる安全なDLQ再試行スケジューリング実装。 運用上の利点と、KafkaとPostgreSQLの役割分担による堅牢なパイプライン構築。
Wayfairのイベント集約システムと失敗時の課題
- Wayfair のプロジェクトにて、 Kafkaイベントストリーム を活用した日次レポート生成システムを担当
- Kafkaコンシューマ がイベントを受信し、外部サービスでデータ補完、 CloudSQL PostgreSQL へ永続化
- 正常時は イベントの流れ がスムーズだが、分散システム特有の 障害発生 が不可避
- 外部APIのダウン・遅延、コンシューマのクラッシュ、不正なイベント構造など多様な 障害シナリオ
- これらの障害を 優雅に処理 するために Dead Letter Queue(DLQ) を導入
Kafka DLQの限界とPostgreSQL DLQへの移行
- 一般的な手法として Kafkaトピック をDLQに利用するが、 可観測性に課題
- 失敗理由別の検索や特定イベントの再試行が 困難
- 「昨日何が失敗したか」等の 簡単な質問にも追加ツールが必要
- CloudSQL PostgreSQL をDLQとして利用することで、 運用複雑性を増やさず に障害イベントを 第一級市民 として管理
- 失敗イベントごとに ペイロード・失敗理由・ステータス を記録
- ステータスは PENDING (未再処理)と SUCCEEDED (再処理成功)の2種類でシンプルに管理
DLQテーブル設計とインデックス戦略
- payload カラムは JSONB 型で生イベントを柔軟に格納
- status でライフサイクルを明確化
- retry_after で過剰な再試行を防止
- retry_count で再試行回数を管理
- タイムスタンプ で監査や運用分析が容易
- 主なインデックス
- status
- status, retry_after
- event_type
- created_at
- これにより再試行対象イベントの効率的抽出や、デバッグ・時系列分析が 高速化
ShedLockによるDLQ再試行メカニズム
- ShedLock を用いた 再試行スケジューラー でPENDINGイベントを定期的に再処理
- サービスが 複数インスタンス で動作しても、ShedLockにより 重複実行防止
- 再試行設定例
- 最大再試行回数:240
- 1回あたりバッチサイズ:50
- 実行間隔:6時間
- 再試行時の流れ
- スケジューラーが FOR UPDATE SKIP LOCKED 付きSQLで安全に対象行を選択
- 成功時は SUCCEEDED へ、失敗時は PENDING で次回以降再試行
- SKIP LOCKED により複数インスタンスが同時に異なる行を処理、 重複再試行防止と高スループット両立
運用上のメリット
- 失敗イベントの可視化 と 監査性 向上
- SQLでシンプルに失敗分析・再処理が可能
- 長時間の外部依存障害でも イベント損失や再試行嵐を回避
- 本質的に不正なイベントも 可視化 され、 サイレントドロップ防止
- 障害対応の 心理的負担軽減 と 明確なリカバリパス の確立
KafkaとPostgreSQLの役割分担と総括
- Kafkaは 高スループットなイベント配送 を担当
- PostgreSQLは 障害イベントの永続化・検索性・再試行管理 を担当
- 各システムの 強みを活かす設計 で、 堅牢かつ運用容易なパイプライン を実現
- PostgreSQL DLQにより障害対応が「退屈で予測可能」になり、 本番運用に最適