
1 つのサーバーで 60 のコンテナ
1 つのベアメタルボックスで数十から数百の Hoody コンテナを実行。KSM と BTRFS のデデュプでマージナルコストはほぼゼロ。
Stripe が ?n=12 付きでパイプパスにイベント本文を POST します。12 のサブスクライバーが同じパスを ?n=12 付きで GET します。パイプは全員が接続するまでメッセージを保持し、その後 12 人全員に同時にストリームします。ブローカーも、コンシューマーグループも、DLQ も不要です。
Hoody Pipe はマルチレシーバーモードを持つ HTTP ストリーミングです。送信者と受信者の両方の URL に ?n=N を追加すると、パイプは N 個のリーダーが接続するまで待機し、その後本文を全員に同時にミラーリングします。遅いものは自分の接続を絞り、速いものは流れ続けます。
Stripe エンドポイントがイベント本文を /api/v1/pipe/billing?n=12 にそのまま転送します。パイプが 12 のレシーバーが集まるのを待つ間、接続はブロックされます。
各サブスクライバーはコンテナ内の curl ループで、同じパスを ?n=12 付きで GET します。パイプは 12 番目のリーダーが接続するまで本文をメモリ内に保持します — オンディスクキューも、フラッシュするものもありません。
全員が接続したら、本文は 12 人全員に一度にストリームされます。遅いリーダーは自分のソケットにバックプレッシャーをかけ、他は進み続けます。最後のリーダーが切断すると、パイプはメッセージを忘れます。
# Sender side — your Stripe webhook handler.
# Pipe holds the body until 12 readers are attached.
curl -X POST "https://api.hoody.com/api/v1/pipe/billing?n=12" \
-H "Authorization: Bearer $HOODY_TOKEN" \
-H "Content-Type: application/json" \
--data-binary "@stripe-event.json"
# Receiver side — one of twelve subscriber containers.
# Same path, same n. Streams the event body when fan-out is ready.
curl -N "https://api.hoody.com/api/v1/pipe/billing?n=12" \
-H "Authorization: Bearer $HOODY_TOKEN" | ./billing-handler.sh
# n must match on both ends — mismatch returns 400.
# Default n=1 is point-to-point. n=12 is fan-out for twelve.同じ URL、同じクエリ文字列、両端共通。送信者の接続がブローカー、リーダーの接続がコンシューマーグループです。トピックがないため、バックプレッシャーはトピック単位ではなくソケット単位です — 1 つのインフライト本文と、それを引っ張る 12 のソケットがあるだけです。
サブスクライバーを追加するのは、別のコンテナ内でもう 1 つの curl を実行するだけです。削除するのは curl を kill するだけです。ブローカー設定も、コンシューマーグループのリバランスも、ドレインする DLQ もありません — クラスタートポロジーはまさに今動いているプロセスそのものです。
パイプは誰がサブスクライブしているかを追跡しません。イベントごとに n 個の接続を待つだけです。両端で n をバンプすると、次のイベントは新しい人数を待ちます。メンバーシップが存在しないため、破損するメンバーシップ状態もありません。
下のすべての行は、ブローカーがプロトコルそのものになると消える作業のカテゴリーです。プロビジョニングするインフラも、学ぶ抽象化もなく — ただ curl と ?n だけ。
SQS も、Kafka クラスターも、RabbitMQ エクスチェンジもありません。パイプがキューであり、一度に 1 メッセージのために生きています。
オフセットも、コミットも、リバランスもありません。パイプは n のソケットが接続するまで本文を保持します — それが調整モデルのすべてです。
送信者が n のリーダーが揃わずに切断した場合、パイプはタイムアウト (5 分 TTL) し、Stripe がリトライします。世話するポイズンメッセージのバケットはありません。
サブスクライバーは curl ループ。送信者は curl。プロトコルは HTTP。URL を叩けるものなら何でもクラスターに参加できます。
遅いリーダーは自分の接続を絞ります。他の 11 はフルスピードでストリームし続けます。フリート全体にわたるヘッドオブラインブロッキングはありません。
本文は最後のリーダーが切断した瞬間に消えます。設定する保持ポリシーも、スケジュールするログ圧縮も、書く GDPR の delete-on-request ジョブもありません。
12 のサブスクライバー、1 つの URL、ブローカーなし。
下にあるブローカーは、HTTP ファンアウトがクエリパラメーターになる前にインストールしていたものです。右側はそれらを置き換えるもの — 1 つのパス、1 つの n、そして自分たちがクラスターであることを知らない 12 の curl プロセスです。
12 のレシーバーが同じパスを同じ n で GET します。パイプがブローカーであり — 最後のリーダーが切断した瞬間にメッセージを忘れます。
Webhook を N 個のコンシューマーにブロードキャストするためにこれらのいずれかに手を伸ばすなら、パイプモデルは 2 回の curl 呼び出しで同じ仕事をします — 片側に送信者、もう片側に受信者。
1 スプリントかけて書いていたファンアウトが、今やクエリパラメーターです。?n=12 を追加して、出荷してください。