Vegas Engineering by FORBIS 記事一覧
← 記事一覧へ戻る
Architecture ・ 第15回

状態変更を、疎結合に伝える — Kafka(MSK)によるイベントハブ連携

在庫・債権・通知…。ひとつの状態変更に多くの後続が反応する。それをイベントで疎結合につなぐ。

Vegas 開発チーム ・ 2026-07-03 ・ 読了 7分

WHY状態変更に、後続が群がる

通販基幹では、ひとつの状態変更が多くの後続処理を呼び起こす。受注が確定すれば、在庫を引き当て、債権を計上し、顧客へ通知し、外部システムへデータ連携する。これらを受注処理から同期的に呼び出すと、呼び出し先が増えるほど処理は肥大し、どれかひとつが遅延・失敗しただけで受注そのものが巻き込まれてしまう。発行する側が「誰が反応するか」を知っている限り、結合は解けない。

そこで、状態変更をドメインイベントとして表現し、マネージドの Kafka(MSK)へ発行する。発行側は「何が起きたか」を宣言するだけで、誰が反応するかは知らない。消費側は各自の関心に応じてトピックを購読する。発行と消費が時間的にも実装的にも切り離される。

FLOW1つの発行、複数の反応

発行側(プロデューサ)はイベントをトピックへ1度書き込むだけでよい。在庫・債権・通知といった消費側(コンシューマ)は、それぞれ独立してトピックを読み、自分の処理を進める。片方が止まっていても、もう片方の処理は影響を受けない。

状態変更 プロデューサ トピック Kafka (MSK) 在庫引当コンシューマ 債権処理コンシューマ 通知コンシューマ
図:1つの状態変更がトピックを介して複数のコンシューマへ疎結合に配信される

GATE入口を、ひとつに統一する

Vegas の中央ゲートウェイは、同期呼び出しやキューだけでなく Kafka レコードも入口として受け取る。届いたレコードをデコードして正規化し、以降は同一の処理系に載せる。呼び出し経路(同期/非同期/イベント)が違っても、業務ロジックは1本にまとまる。

同期呼び出し キュー(非同期) Kafka レコード ゲートウェイ デコード・正規化 同一の処理系
図:3つの入口を1つのゲートウェイへ集約し、業務ロジックを一本化する

CODEレコードを受けて処理に載せる

Kafka レコードの値は base64 でエンコードされて届く。ゲートウェイはこれをデコードしてイベントとして復元し、既存の処理系へ引き渡す。

gateway_kafka_handler.pyPython
def handle_kafka(records):
    for topic, msgs in records.items():
        for m in msgs:
            # 値は base64。デコードしてイベントへ復元
            raw = base64.b64decode(m["value"])
            event = decode_event(raw)

            # 冪等性:同一キーの再処理は握りつぶす
            if already_processed(event.dedup_key):
                continue

            # 同期/キューと同じ処理系に載せる
            dispatch(event)
            mark_processed(event.dedup_key)

TRADEOFF疎結合の代償を、設計で払う

疎結合は多くを与えるが、無償ではない。得られるのは、発行側と消費側の独立、消費側を後から追加できる拡張性、スパイクをトピックが吸収する耐性、そしてオフセットを戻して再処理できる回復性である。一方で、次の代償を設計で払う必要がある。

要は、同期の「その場で分かる」明快さを手放す代わりに、拡張性と耐障害性を得る取引だ。即時整合が絶対の処理まで無理にイベント化しないこと、逆に波及の広い状態変更はイベントに寄せること。その線引きが設計の勘所になる。

TAKEAWAY

状態変更をドメインイベントとして Kafka(MSK)へ発行し、入口をゲートウェイに集約すれば、発行側と消費側は独立して進化できる。代わりに順序・重複・観測・スキーマ進化の管理が必須で、冪等処理を前提に据えることが疎結合を成立させる条件になる。