すべてを疎結合にする。サービスが互いの稼働時間に関する期待ではなく、イベントを通じて通信するようにする。

モノリスがデプロイメントのボトルネックになっている — あらゆる変更にチーム間の調整が必要で、課金システムにバグがあるとアプリケーション全体が停止してしまう。または、異なる機能が異なる速度で進化する新しいシステムを構築している場合:注文管理は毎週変更されるが、在庫ロジックは四半期ごとに変更される。カスケード障害チェーンを引き起こす同期的な API 呼び出しではなく、イベントを通じて通信することで、独立して開発、デプロイ、スケーリングできるサービスが必要になる。
イベント駆動型マイクロサービスは、システムを独立してデプロイ可能なサービスに分解し、主に非同期イベントを通じて通信します。各サービスは自身のデータを所有し、状態が変化したときにドメインイベントを発行し、他のサービスからのイベントに反応します。これにより、時間的結合が排除されます — サービス A はその作業を行うためにサービス B が実行されている必要がありません。このパターンには、書き込みモデルと読み取りモデルを分離するための CQRS (Command Query Responsibility Segregation)、状態変更の完全な履歴をキャプチャするためのイベントソーシング、分散ロックなしでマルチサービス間トランザクションを管理するための saga orchestration が組み込まれています。
Explore more design patterns and system architectures
MicrocosmWorksは、Apache KafkaやAmazon EventBridgeのような永続的なメッセージブローカーを備えたイベント駆動型システムを設計しており、コンシューマーがイベントを正常に処理するまでイベントを保持することで、障害発生時のデータ損失を防ぎます。障害が発生したマイクロサービスがイベントパイプライン全体をブロックしないよう、デッドレターキュー、指数バックオフ再試行ポリシー、およびサーキットブレーカーを実装しています。ダウンストリームサービスが復旧すると、手動介入なしで未処理のイベントに自動的に追いつきます。
イベント駆動型通信は、サービスが即時の応答を必要としない場合、デプロイメントサイクルを分離する必要がある場合、または単一のアクションが複数のダウンストリームプロセスをトリガーする場合に優れた選択肢です。MicrocosmWorksは通常、注文処理、通知パイプライン、分析データの取り込みにイベント駆動型パターンを推奨しており、一方、秒未満の応答を必要とするユーザー向けクエリには同期 API を維持しています。私たちが構築する多くの本番システムでは、同期読み込みと非同期書き込みを組み合わせたハイブリッドアプローチを採用しています。
MicrocosmWorksは、Kafkaトピックでパーティションキーベースの順序付けを使用し、特定のエンティティ(特定の注文やユーザーなど)に関連するすべてのイベントが同じコンシューマーインスタンスによって順序通りに処理されることを保証しています。エンティティをまたいだ順序付けが必要なシナリオでは、冪等性のあるイベントハンドラを備えたsaga orchestratorsを実装し、順不同のメッセージを安全に再処理できるようにしています。また、イベントペイロードにvector clocksやsequence numbersを埋め込むことで、コンシューマーが順序付けの競合を検出し、解決できるようにしています。
MicrocosmWorksは、compensating transactionsを伴うSaga patternを実装しています。これにより、各マイクロサービスはローカルなtransactionを完了した後にdomain eventsを発行し、ダウンストリームのサービスがそれに応じて反応するか、または障害時にrollback compensationsをトリガーします。私たちはこれを、ビジネスデータとともにイベントをローカルなoutbox tableにアトミックに書き込み、その後message brokerに確実に発行するoutbox patternと組み合わせています。これにより、two-phase commitsのパフォーマンスと信頼性のペナルティなしにeventual consistencyを実現します。
MicrocosmWorksは、OpenTelemetryを使用して、すべてのイベントに相関IDと分散トレーシングヘッダーを組み込んでいます。これにより、JaegerやGrafana Tempoのようなツールで、参加するすべてのマイクロサービスにわたるビジネス取引の完全なライフサイクルを可視化できます。また、サービスごとのスループット、コンシューマーラグ、処理レイテンシを表示するリアルタイムのイベントフローダッシュボードも構築しており、ボトルネックを特定しやすくしています。当社の標準的なオブザーバビリティスタックには、イベントメタデータを含む構造化ロギングが含まれており、単一のイベントでもプロデューサーからすべてのコンシューマーまで数秒で追跡できるようにしています。
このアーキテクチャは、サービス間でドメインイベントをルーティングする イベントバックボーン (Kafka, EventBridge, または NATS) を中心に構築されています。各サービスには3つの境界があります:受信リクエストを処理してイベントを発行する コマンドハンドラ、読み取りに最適化されたプロジェクションを提供する クエリハンドラ、および他のサービスからのイベントに反応する イベントプロセッサ です。Saga Orchestrator は、イベントをリッスンし、ステップが失敗したときに補償コマンドを発行することで、多段階のビジネスプロセス(例:注文処理)を調整します。
| レイヤー | テクノロジー |
|---|---|
| コンピューティング | Node.js (NestJS), Python (FastAPI), Go — ワークロード特性に基づきサービスごとに選択 |
| メッセージング | Apache Kafka (MSK), AWS EventBridge, NATS JetStream, RabbitMQ |
| データ | PostgreSQL (トランザクション), DynamoDB (キーバリュー), Redis (キャッシング/ロック), EventStoreDB |
| オーケストレーション | Temporal (ワークフローオーケストレーション), AWS Step Functions, カスタムSagaコーディネーター |
| 可観測性 | OpenTelemetry (分散トレーシング), Datadog, Jaeger, 相関ID付き構造化ロギング |
| 利用すべき場合 | 避けるべき場合 |
|---|---|
| 複数のチームが異なる周期で独立してデプロイする必要がある | チームが5人未満のエンジニアである場合 — 適切に構造化されたモノリスの方が運用がシンプル |
| システムの異なる部分が異なるスケーリング特性を持つ | MVPを構築中で迅速なリリースが必要な場合 — 分散システムは構築に時間がかかる |
| 強力な監査証跡とイベントリプレイ機能が必要 | すべての操作が同期的な、強力な整合性を持つ応答を必要とする |
| ドメインが自然な境界づけられたコンテキスト(注文、支払い、在庫)を持つ | ドメインが密結合している場合 — 分割すると分散モノリスになる |
MW は、技術レイヤー(API サービス、データサービス、認証サービスなど)でマイクロサービスに分解することはありません。私たちは、DDD (Domain-Driven Design) の境界づけられたコンテキストを使用して、ドメイン境界に沿って分解します。コードを書く前に、イベントストーミングワークショップを実施して、ドメインイベント、コマンド、集約をマッピングします — これがサービス境界を決定するものであり、技術的な好みが決定するものではありません。私たちはエンタープライズクライアント向けにモノリスをイベント駆動型アーキテクチャに移行してきましたが、最も一般的な教訓は次のとおりです:まずは少数の大きなサービスから始め、後で分割することです。
モデルはそれ自体で動作するわけではありません。モデルのトレーニング、検証、デプロイ、監視を行うパイプラインこそが実際の製品であり、モデルはその成果物の一つに過ぎません。