2025年にリアルタイム更新が必要なら、通常はFirebase Realtime Database、Supabase Realtime、Pusher、Ably、ホスティングされたWebSocketレイヤーなどを使います。接続クライアントへの更新配信の複雑さを抽象化してくれます。機能する間は、よく機能します。
Atlas Verifiedは、リアルタイム購読を含む管理型データベースから始めました。成長に伴い、抽象化の限界に直面しました。接続プールの制限、リアルタイムの信頼性問題、PostGIS空間照会の必要性、独自トリガーロジックへの要望が、データベースレイヤーの制御を取り戻す方向へ導きました。
自己ホストのPostgreSQLへ移行し、標準のLISTEN/NOTIFY機構とServer-Sent Eventsでリアルタイムシステムを構築しました。判断の理由、構造、学びを説明します。
管理型プラットフォームを離れた理由
管理型データベースは、認証、行レベルセキュリティ、リアルタイム購読、自動API、ダッシュボードをすぐに提供する魅力的な価値があります。初期製品には有用で、バックエンドコードを一行も書かずに機能するアプリを作れます。
成熟して要件がプラットフォームの想定から離れると、問題が現れます。
接続制限。 管理型では、独自制限を持つプール管理機構を介することがよくあります。APIサーバー、バックグラウンドワーカー、リアルタイムリスナーなど、個別の接続プールが必要な複数サービスがあると、すぐに接続を使い切ります。実際の製品問題ではなく、プール管理の制限回避に開発を費やしていました。
リアルタイムの信頼性。 管理型のリアルタイムはPostgreSQLのWrite-Ahead Logを用いるChange Data Captureで動いていました。構造は洗練されていますが、制御できない障害を生みました。WALベースの複製には遅延があり、サービスが遅れて古い更新を届けることがありました。通信中断後の再接続は不安定で、調査には制御できない基盤へのアクセスが必要でした。
拡張機能の要件。 当社は港の位置、航路、船舶位置などの地理データを含む貿易書類を処理します。PostgreSQLの空間拡張PostGISは不可欠です。管理型でも対応していましたが、必要な特定の版や設定を常に利用できるわけではありませんでした。
独自のトリガーロジック。 一般的な"行が変更された"通知だけでなく、アプリ固有のイベントを発行するトリガーが必要でした。文書処理状況の変更では、アップロードした特定の接続クライアントに通知する必要があります。管理型は表単位でしたが、当社には対象単位が必要でした。
移行は費用や信条の問題ではなく、実務的な判断でした。機能を自作するより、制限回避に多くの時間を費やしていたためです。
LISTEN/NOTIFY:PostgreSQLに隠れたPub/Sub
PostgreSQLは2010年公開の9.0から、発行・購読機構を内蔵しています。15年以上経つのに、LISTEN/NOTIFYは驚くほど利用されていません。多くの開発者は存在を知りません。
仕組みは簡単です。どの接続も名前付きチャネルでLISTENを実行して購読し、NOTIFYで全リスナーへ送信できます。ペイロードは文字列で、8,000バイトが上限です。
リアルタイムアプリで強力な理由:
追加基盤の負担なし。 別のメッセージブローカーの導入、監視、拡張は不要です。PostgreSQLがあればPub/Subがあります。この用途ではRedis、RabbitMQ、Kafkaは不要です。
トランザクションの保証。 NOTIFYは、それを含むトランザクションがコミットされたときだけ配信されます。行を挿入して通知を送っても、ロールバックされれば届きません。外部ブローカーでは、慎重な統合制御なしには得られない特性です。
トリガー統合。 PostgreSQLトリガーは実行時にpg_notifyを呼べます。書き込み経路にアプリコードを置かず、特定データの変更時にデータベースから自動通知できます。
実際の制限もあり、理解が必要です:
永続化なし。 NOTIFY時にリスナーがなければ、メッセージは失われます。再生、キュー、切断クライアントへの配信保証はありません。リスナーが再接続と状態復元を扱う必要があります。
ペイロードの大きさ。 通知の8,000バイト制限により、大きなオブジェクトは送れません。表名、操作種類、主キーという最小限の内容を送り、必要ならクライアントが全データを取得します。
単一データベースの範囲。 LISTEN/NOTIFYは一つのPostgreSQLインスタンス内で動き、レプリカやクラスターをまたぎません。すべての書き込みが単一のプライマリーに向かう構造では、制限になりません。
当社の構造:トリガー、SSE、チャネルの多重化
各部分は次のように連携します。
データベーストリガー は、文書、メッセージ、会話、通知、出荷検証など、リアルタイム更新が重要な表に設置します。行の挿入、更新、削除で起動し、表名、操作種類、主キー、絞り込み列を含むJSONペイロードでpg_notifyを呼びます。
専用のリスナー接続 がAPIサーバーで通知チャネルにLISTENを実行し、全トリガーイベントを受け取ります。照会用接続プールから分離した長期間の専用接続で、通知を聞くだけの役割です。
イベントバス が通知を受け取り、購読内容に応じて接続クライアントへ振り分けます。特定出荷IDの文書を購読するクライアントは、その出荷の文書だけの通知を受けます。
Server-Sent Events がブラウザーへ通知します。各クライアントは、希望のチャネルと絞り込みを指定し、一つのSSE接続を開きます。イベントバスが通知と購読内容を照合し、該当するSSE接続で配信します。
WebSocketsよりSSEを選ぶ理由
この判断には一貫して満足しています。当社の用途で重要なあらゆる側面で、Server-Sent EventsはWebSocketsより簡単です。
設計上、単方向。 必要なのは、データ変更をサーバーからクライアントへ伝えることです。クライアントからの送信には標準HTTP要求を使い、リアルタイム送信は不要です。SSEの単方向モデルが実際の要件に合います。
HTTP標準。 SSEは特定のコンテンツ種別を持つ標準HTTP要求です。特殊設定なしでHTTPプロキシ、ロードバランサー、CDNを通れます。WebSocketsにはHTTP Upgradeが必要で、一部のプロキシは正しく処理せず、企業ファイアウォールでは完全に遮断されることもあります。
自動再接続。 ブラウザーのEventSource APIが標準で再接続を扱います。切断時は指数的に待機時間を増やして自動再接続します。WebSocketsでは自作する必要があり、少なくとも一度は誤ります。
WebSocketsが優位な双方向通信は、当社には不要です。リアルタイムのクライアントからサーバーへの送信が必要ならWebSockets、サーバーからの通知配信ならSSEが適しています。
ORMなしの照会レイヤー構築
管理型プラットフォームを離れると、自動生成の照会APIも失いました。APIサーバー向けのデータベースアクセスレイヤーが必要でした。
一般的な選択肢はPrisma、TypeORM、DrizzleなどのORMか、ドライバーでの生SQLです。当社は第三の道、連結可能なAPIを提供しながら内部で生SQLを生成・実行する軽量クエリビルダーを選びました。
使い慣れたAPI。 既存コードは管理型のクライアントライブラリー向けでした。互換APIにより、移行の変更を最小限にできました。以前の照会を同一の構文でクエリビルダーから実行できます。
隠れた処理なし。 ORMは見えず、ときに制御できないSQLを生成します。遅い照会では、元の呼び出しと似ていない生成SQLを読む必要があります。当社のビルダーは予測可能で、各連結メソッドが特定のSQL句に対応し、常に生成結果を確認できます。
埋め込み結合。 貿易データは関係型です。出荷に文書があり、文書にノードがあり、ノードに検証チェックがあります。毎回複雑なJOINを手書きせず、入れ子の選択と結果を扱えることは、開発体験の大きな改善です。
結果として、数百行のコードで大半のデータベース操作を扱い、常に読んで最適化できるSQLを生成する照会レイヤーになりました。
接続プールの予算管理
自己ホストでは、接続予算も自ら管理します。max_connectionsが絶対的な上限を定め、各接続はメモリーを消費します。
接続をサービス間で共有する有限の予算と考えると、計画しないチームが遭遇する一群の問題を防げると分かりました。
各サービスが最大接続数を宣言します。合計はPostgreSQL上限を十分下回り、psql、移行スクリプト、監視などの随時接続の余裕を残す必要があります。当然に見えても、本番で枯渇するまで行わないチームが大半です。事前に予算化して、午前3時の呼び出しを避けました。
大規模で安全な移行
自己ホストへの移行では、数百の表、関数、トリガー、索引を動かしました。より大きな課題は、アプリの進化とともに機能し続ける移行システムでした。
自動移行では、タイムスタンプ付きのファイルを専用ディレクトリーに置きます。実行機構が走査し、適用済みを記録する管理表と比べ、未適用の移行を順に実行します。各移行はトランザクション内で動き、失敗すれば完全にロールバックし、修正まで配備を止めます。
各配備で、アプリ開始前に自動実行します。手作業なしに配備の一環でスキーマを変更します。開発者がタイムスタンプ付きSQLファイルをリポジトリーへ送れば、次の配備で適用します。
安全性を保つ判断は、部分適用でも失敗しない冪等性の保護、人の入力なしに動く自己完結したSQL、失敗時の全体ロールバックです。部分適用されたスキーマのままアプリは開始しません。
得られたもの
独自リアルタイムを備えた自己ホストPostgreSQLへの移行は、大きな開発投資でした。しかし、成果も大きなものでした:
信頼性。 データ変更後、ミリ秒単位で通知が届きます。WAL複製遅延も、重要な経路の第三者サービス停止もありません。
調査しやすさ。 問題時には、トリガー起動、通知送信、イベントバスの振り分け、SSE配信の全経路を追跡できます。すべてが自社コード、ログ、基盤にあります。
柔軟性。 新しい表へのリアルタイム追加は、トリガーを設置する一つのSQL移行で済みます。設定画面、第三者ダッシュボード、サポート依頼は不要です。
性能。 調整済みプールによる直接接続は、管理型基盤を経由する接続を上回ります。移行後、照会遅延が明確に減りました。
代償は運用責任です。データベース管理、バックアップ、複製監視、容量計画を担当します。PostgreSQL運用に慣れたチームには管理可能ですが、そうでなければ管理型の抽象化は制限に見合う価値があるかもしれません。
Atlas Verifiedは独自のリアルタイム基盤を備えた自己ホストPostgreSQLで稼働し、世界のサプライチェーン全体で毎日数千件の貿易コンプライアンス検証を処理します。
