在庫データが数分で陳腐化し、結果として「在庫あり」と表示されながら注文が通らない。このギャップを生むのが、多くのECシステムが今も採用するバッチ同期の構造的な限界です。Apache Kafkaは、この問題に対してイベントストリーミングという全く異なるアプローチで対処します。
なぜバッチ同期は限界なのか
バッチ処理(batch processing)とは、一定時間ごとにまとめてデータを転送・集計する方式です。夜間の在庫同期はその典型で、POS(Point of Sale、店頭の販売管理システム)とWMS(Warehouse Management System、倉庫管理システム)、ERPがそれぞれ数時間〜1日おきにデータを突き合わせます。
問題は、更新と更新の間に発生した変化が見えないことです。たとえば、ある商品の在庫が15時に倉庫で欠品になっても、夜間バッチが走るまでECサイトは「在庫あり」と表示し続けます。売れれば売れるほど過剰受注が積み上がり、キャンセル対応が発生します。
複数チャネル(実店舗・ECサイト・マーケットプレイス)にまたがる販売が増えるほど、この問題は指数的に複雑化します。それぞれのシステムが独自の在庫スナップショットを持ち始め、データの整合が取れなくなるからです。
Kafkaがイベント駆動アーキテクチャを実現する仕組み
Apache Kafkaはイベントストリーミング基盤です。ここでいう「イベント」とは、「商品Aを1個販売した」「倉庫Bから倉庫Cへ50個移送した」など、在庫に影響する出来事そのものをメッセージとして記録したものです。
Kafkaはこれらのメッセージをトピック(topic)と呼ばれるカテゴリ別のストリームに書き込みます。販売イベントなら `inventory.sales`、補充なら `inventory.replenishment` といった分類です。各システム(ERP・WMS・ECプラットフォームなど)はコンシューマー(consumer)として必要なトピックを購読し、イベントが届いた瞬間に自分のデータを更新します。
このアーキテクチャを図で示すと次のような流れになります。
POS / ECサイト / IoTセンサー
↓ publish
Kafka Topics (inventory.*)
↓ subscribe
WMS / ERP / 補充システム / 需要予測モデルバッチのように「どちらかが定期的にポーリングする」のではなく、イベントが発生した瞬間に全受信者に伝播する点が本質的な違いです。
具体的なイベントスキーマと実装上の考慮点
Kafkaで在庫イベントを設計するとき、メッセージのスキーマが重要になります。在庫イベントには最低限「SKU(商品コード)・変化量・タイムスタンプ・発生元システムID」が含まれるのが一般的です。
{
"event_type": "sale",
"sku": "ITEM-9981",
"quantity_delta": -1,
"location_id": "store-tokyo-03",
"timestamp": "2025-07-10T14:32:01Z",
"source_system": "pos-v2"
}スキーマを厳密に管理するために、Schema Registry(Confluent社が提供するスキーマ管理ツール)と組み合わせるのが現場での標準的な構成です。Avroやprotobufでスキーマを定義しておくと、異なるシステム間での互換性検証が自動化できます。
処理の信頼性を高めるには、Kafkaのパーティション(partition)設計も欠かせません。パーティションとは、同一トピックを複数の並列ストリームに分割する機能です。SKUやロケーションIDをパーティションキーにすると、同じ商品のイベントは常に同じパーティションに割り当てられ、順序保証が得られます。在庫の加算・減算の順番が狂うと残高計算が壊れるため、これは設計上の必須要件です。
WebブラウザへのリアルタイムデータプッシュとKafkaの関係
フロントエンドの視点では、Kafkaは直接ブラウザと通信しません。Kafkaのイベントをブラウザまで届けるには、Kafkaコンシューマー側のAPIサーバーがWebSocket(双方向通信プロトコル)やServer-Sent Events(サーバーからブラウザへの一方向ストリーミング)を使って中継する構成が取られます。
たとえば、在庫管理ダッシュボードをNext.jsで構築する場合、APIルートでKafkaから読み取ったデータをSSE(Server-Sent Events)でクライアントにプッシュする実装が現実的な選択肢です。Vercelのエッジランタイム環境ではSSEの扱いに制約があるため、このようなストリーミング系の用途はNode.jsランタイムで動かすか、もしくはWebSocket専用サーバーを別途立てる構成になります。
KafkaとRabbitMQの比較
メッセージキューの選択肢としてRabbitMQと比較されることが多いです。RabbitMQ(ラビットMQ)はキュー型のメッセージブローカーで、メッセージをコンシューマーが受け取ると削除されます。これに対してKafkaはログ型の設計で、メッセージを一定期間(デフォルト7日)保持します。
- RabbitMQ: コンシューマーが受け取ると削除。ルーティングが柔軟。マイクロサービス間の命令伝達に向く
- Kafka: ログとして保持、複数コンシューマーが独立して読み取れる。高スループットのイベントストリームに向く
在庫イベントのように「WMS・ERP・需要予測モデルが同じデータをそれぞれ読む」シナリオはKafkaの得意領域です。
在庫データのストリーミングをどこまでフロントエンドに近づけるかは、エッジランタイムの進化とも連動しています。Cloudflare WorkersやDeno Deployがネイティブなストリーミング対応を強化するにつれ、Kafkaとブラウザの距離はさらに縮まっていくでしょう。