要点
- お金を受け取る処理を、それ以外のすべてから分離する。
- 顧客への応答前に完了する必要のない処理にはイベントを使う。
- 各サービスが自分のデータを持ち、共有テーブルではなくイベントで共有する。
- リクエストがサービスをまたぐなら、分散トレーシングは必須。
注文、決済、メニュー、配車がひとつのアプリケーションを共有していると、ひとつの遅いコンポーネントが決済を止めることがあります。イベント駆動設計がどのように障害を分離するか、そしてその代償を解説します。
ピークの問題
フードデリバリーの需要は食事時に急激なピークを迎えます。ひとつのアプリケーションでは、メニュー閲覧、おすすめ、配車、決済が同じスレッド、接続、メモリを奪い合います。ある領域の遅いクエリが、決済に必要な資源を使い果たすことがあります。
お金を受け取る処理を守る
最初の設計原則は単純でした。他のすべてが劣化しても、注文と決済の処理は動き続けなければならない。そのため、注文と決済を独自のデータストアを持つサービスに分け、それらとの他のやり取りをすべて非同期にしました。
待てる処理はすべてイベントに
注文が入ったとき、顧客にはすぐに確認が必要です。店舗への通知、配達員の割り当て、分析の更新は少し後でも構いません。「注文受付」イベントをKafkaに発行すれば、それぞれの利用側が自分のペースで処理でき、失敗しても注文そのものには影響しません。
- 注文サービス:注文を受け付け、イベントを発行する。
- 店舗サービス:イベントを受け取り、厨房の画面を更新する。
- 配車サービス:イベントを受け取り、配達員を割り当てる。
- 通知サービス:ステータスのイベントに応じて顧客に知らせる。
各サービスが自分のデータを持つ
注文と決済にはトランザクションが必要なのでPostgreSQLに、メニューは店舗ごとに形が変わるドキュメントなのでMongoDBに置きました。サービスは互いのテーブルを読まず、必要なデータはイベントを受け取って最新に保ちます。
その代償
イベント駆動のシステムは、ひとつのアプリケーションより理解が難しくなります。データは結果整合になり、サービス間で障害が起こり得て、デバッグには複数のプロセスをまたいでリクエストを追う必要があります。分散トレーシング(今回はZipkin)と冪等なコンシューマーが、このアーキテクチャを扱えるものにするための最低限の投資です。
小さな社内ツールなら過剰設計です。ピーク時に決済が動き続けることに売上がかかっているプラットフォームにとっては、正しいトレードオフです。
参考になりましたか?次の記事をメールで受け取れます。

