ブローカー肥大化への反論
SQS、Kafka、RabbitMQのような専用のメッセージブローカーは、多くの場合、隠れた運用上のオーバーヘッドを大幅に増加させます。個別のインフラストラクチャを管理する必要があり、プロビジョニング、デプロイ、監視、スケーリングといった個別のサービスにコストがかかります。これはネットワーク遅延を招くだけでなく、複数の分散システムを統合・デバッグする開発者の認知的負荷を決定的に増大させ、スタックに不必要な複雑さを強いることになります。
既存の Postgres データベースは、ブローカーの肥大化を解消する堅牢で信頼性の高い代替手段となります。ACID準拠 と実戦で鍛えられたトランザクション能力の上に構築されたPostgresは、信頼性の高いキューイングのための実証済みの基盤を提供し、障害発生時でもデータの整合性を保証します。数百万行のデータや毎秒数千のリクエストを余裕を持って処理でき、例えば2 CPU、2GB RAMの環境でのテストでは、10万件のメッセージを9秒で処理し、平均して毎秒11,100件のメッセージを処理しました。
PGMQ は、この強力なパターンを軽量でシンプルな拡張機能として形式化したものです。Postgres内で直接SQSライクなAPIを提供し、キューの作成、遅延オプション付きのメッセージ送信、そして「exactly-once(厳密に1回)」の配信を保証する可視性タイムアウト(VT)付きのメッセージ消費を可能にします。つまり、スタックに新しいサービスを一切追加することなく、Rust、Python、TypeScript用のクライアントライブラリを備えた、完全に機能するメッセージキューを手に入れることができるのです。
5行のSQLでキューを構築
純粋なSQLでキューを作成します。pgmq.create('my_queue') を呼び出すだけで、各キューが独自のPostgresテーブルになります。メッセージの送信は pgmq.send('my_queue', '{"job_id": 123}') を使用します。これにより、メッセージがJSONとしてPostgres内に直接埋め込まれ、データモデルが簡素化されます。
pgmq.send() を使ってスケジュール配信を実装します。delay パラメータを追加するだけです(例: pgmq.send('my_queue', '{"task": "future"}', 30))。メッセージはキューに入りますが、30秒間は消費できない状態となり、外部のcronサービスなしで高度なジョブスケジューリングが可能になります。
pgmq.read('my_queue', 30, 1) を通じてメッセージを消費します。重要な vt(可視性タイムアウト)パラメータにより、読み取られたメッセージは指定された期間(例: 30秒)の間、不可視状態になります。これにより exactly-once配信 が保証され、アクティブな期間中に他のワーカーが同じメッセージを処理することはありません。VT内に処理または削除されない場合、メッセージは再びキューに現れます。
処理が完了したらメッセージを削除します。pgmq.delete('my_queue', message_id) を使用してメッセージを完全に削除します。あるいは、pgmq.archive('my_queue', message_id) を使用すると、アクティブなキューからメッセージを削除し、専用のアーカイブテーブルに移動させることができます。これにより、監査や再処理のための履歴ログが保持されます。
しかし、本当にスケーリングするのか?
「でも、スケーリングしないでしょう?」という声が聞こえてきそうです。これは、データベースをキューとして使うことに対する一般的な反論です。しかし、Postgresは数百万行のデータや毎秒数千のリクエストを余裕を持って処理できます。PGMQはこの本来の能力を活用し、分散アプリケーションにおいて弱点と思われていたものを強みに変えます。
最近のストレステストで、リソースが制限された環境におけるPGMQのパフォーマンスが検証されました。研究者は、わずか 2 CPU、2GB RAM のDockerコンテナを用意し、PGMQキューに10万件のメッセージを注入しました。このセットアップは一般的なライブサービス環境を模しており、その結果は非常に説得力のあるものとなっています。
100の並行ワーカーが、わずか9秒で10万件のメッセージすべてを処理しました。各ワーカーはバッチ単位でメッセージの読み取り、ログ記録、削除を行いました。これは、合計スループットが毎秒11,100メッセージを超えることを意味します。詳細なドキュメントやその他の例については、公式のPostgres Message Queue (PGMQ)リポジトリを参照してください。
このようなパフォーマンスは、「スケールしない」という神話を、実質的にあらゆる実世界のアプリケーションにおいて明確に否定するものです。PGMQは、Postgresがメッセージキューとして実行可能であるだけでなく、非常に高性能であることを証明しており、ほとんどのユースケースにおいて専用ブローカーの運用オーバーヘッドを排除します。インフラストラクチャをシンプルに保ちましょう。
この記事が気に入ったら、毎朝同じようなものをメールで受け取れます。
1日1通 · 2クリックで解除 · サードパーティのトラッキングなし
PGMQをアプリケーションに統合する
PGMQをアプリケーションスタックに直接統合しましょう。一般的な言語向けの堅牢なクライアントライブラリを使用して、生のSQLを超えた開発を実現します。公式サポートによりPythonおよびRustの統合が強化され、慣用的なインターフェースを提供します。コミュニティ主導のライブラリにより、PGMQはRubyや複数のTypeScriptフレーバー(Prismaとのシームレスな連携を含む)にも拡張されています。
最小限のコードでプロデューサーを構築します。Pythonのプロデューサーは、キュー名とJSONペイロードを指定するシンプルなsend()呼び出しでメッセージを送信します。これはSQLコマンドのpgmq.send()を反映しており、データベース操作を抽象化します。
ワーカーはメッセージを効率的に消費します。クライアントライブラリのread()関数を使用してメッセージのバッチを取得し、可視性タイムアウト(VT)を尊重します。処理後、delete()またはarchive()を呼び出してメッセージを削除することで、正確に1回の配信(exactly-once delivery)を保証し、再処理を防ぎます。このパターンは大容量のタスクを処理します。
データ層とメッセージング層をPostgres内に統合することで、インフラストラクチャが簡素化されます。個別のメッセージブローカーの運用オーバーヘッドを排除し、ネットワーク遅延と認知的負荷を軽減します。この統合により、開発、テスト、デプロイが効率化され、より堅牢で保守性の高いシステムが実現します。
よくある質問
PGMQとは何ですか?
PGMQ (Postgres Message Queue) は、PostgreSQL用の軽量な拡張機能であり、データベース内で直接メッセージキューイング機能を実現します。AWS SQS、RabbitMQ、Kafkaなどのサービスに代わる選択肢を提供します。
PGMQはどのようにして正確に1回の配信(exactly-once delivery)を保証しますか?
PGMQは「可視性タイムアウト」を使用します。メッセージが読み取られると、一定期間、他のコンシューマーからは見えなくなります。コンシューマーはその期間内にメッセージを削除またはアーカイブする必要があります。失敗した場合、メッセージは再び表示され、別のコンシューマーが処理できるようになるため、データの損失を防ぎます。
PGMQは本番環境レベルのトラフィックを処理できますか?
はい。ベンチマークによると、PGMQは控えめなハードウェア(例:2-CPUコンテナ)で毎秒11,000件以上のメッセージを処理できます。これは、多くの大容量分散アプリケーションにとって十分すぎる性能です。
Postgresをメッセージキューとして使用する主な利点は何ですか?
主な利点はインフラストラクチャの簡素化です。既存のデータベースを活用することで、依存関係を減らし、運用オーバーヘッドを下げ、一般的なユースケースにおいてパフォーマンスを犠牲にすることなく技術スタック全体を簡素化できます。

