Postgresでキューを爆速スケールさせる!実践的チューニング術
Making Postgres queues scale
Making Postgres queues scale
PostgreSQLをメッセージキューとして利用する際、スケーラビリティを確保するための技術的なアプローチや最適化手法について議論する。
「Postgresベースのキューはスケールしない」っていうのはよくある定説だけど、それはもう10年前の話かもね。ここ数年でPostgresを活用したキューイングシステムは増えてるし、3年以上前からRailsだってデフォルトでPostgresベースのキュー(SolidQueue)を採用してるよ。
間違いなくスケールするよ。今さら議論の余地もないと思う。宣伝になっちゃうけど、Obanの処理性能に関する過去記事を貼っておくね(https://oban.pro/articles/one-million-jobs-a-minute-with-oban )。その後の調査でも、秒間1万2000件の処理を維持しつつ、p99を100ms以下に抑えられてるよ。
Postgresでのキューイングに関する記事を読むたびに既視感を覚える。みんなこういう記事を書くのが好きなんだよね。
DBOSの記事で完全にスルーされてるパフォーマンスの落とし穴が「肥大化(bloat)」の問題。PostgresのMVCCの仕組み上、処理済みの行を更新したり削除したりするとデッドタプルが蓄積されちゃうんだよね。これは深刻な問題で、クエリプランナーの判断に悪影響が出る。デッドタプルもインデックスの一部として扱われるし、それをスキップするコストはプランナーに考慮されないから、テーブルがデッドタプルだらけになると性能がガタ落ちする。オートバキュームが常に追いつかない状態になるから、かなりアグレッシブな設定が必要になるはず。
うちのチームでは新しいアプリにPgQue [1]を使い始めたんだけど、これはかなりうまく設計されてる。PgQueは削除処理を避けることで肥大化問題を回避するように作られてるんだ。処理済みのタプルを消すんじゃなくて、テーブルごと定期的にTRUNCATEする仕組み。2つのテーブルを切り替えて運用するから、片方を使っている間にもう片方をTRUNCATEできる。スナップショット方式を使って行ロックを避けているのもポイントだね。
PgQueの面白いところは、位置ベースのキューモデルを採用している点で、協調コンシューマー、ファンアウト、アトミックなバッチ処理、「最後成功した地点からのリカバリ」みたいな気の利いた機能が実装できる。優先度サポートがないとか、少しレイテンシが高いといった妥協点はあるけど、ほとんどの用途では問題にならないよ。
過去にHNでも議論されてる [2]。
[1] https://github.com/NikolayS/pgque
[2] https://news.ycombinator.com/item?id=47817349
これって手動で投稿されてるの?それともClaudeとの共同作業タスクか何かでスケジュールされてるの?
仕事で「そこそこの規模(特にテナント間の公平なキューイングが必要な場合)でPGをキューに使っていいのか」っていう議論になったことがあるんだよね。
探してみると、「実際にやってみたけど後悔してる」っていうHNのコメントが結構たくさん出てきてさ。
そこで聞きたいんだけど、ある程度のスループットがあるシステムで、競合が発生しうる環境下でも「PGをキューに使って後悔してない」っていう人いる?