マイクロサービスの課題を克服するsagaパターンについて
最近、「マイクロサービス」や「分散処理」について考えていました。
その際に、DynamoDBやMongoDBなど、一貫性に弱点のあるDBはどのようにトランザクションを克服しているのか気になりましたので、その際に使用する手法の一つであるsagaパターンを紹介します。
sagaパターンで解決できる課題
マイクロサービス化を行うことで主に下記のような問題が出るかと思います。
- トランザクション管理の複雑性
- エラー処理とロールバック
- 各サービスの状態管理と一貫性の確保
- サービス間の疎結合性の維持
こういった課題に対するアプローチとして、sagaパターンを用いることで軽減することができます。
sagaパターンとは
Sagaパターンは分散システムでサービス間のトランザクションを管理し、一貫性を保証する設計の一つです。
代表的な2つのアプローチがあります。コレオグラフィとオーケストレーションです。
オーケストレーション
オーケストレーションパターンは、中央のオーケストレーターが全体のビジネスプロセスを制御し、各サービスの操作を調整する方法を指します。オーケストレーターが各サービスを呼び出し、エラー処理、プロセス全体のフローを管理します。
構成
画像のようにBでエラーが発生した場合、オーケストレーターから補償トランザクションを実行します。
補償トランザクションでは、前のサービスで行われた処理を実行前に戻すような処理を行います。
メリット
トレーサビリティ性が高い
中央のオーケストレーターがすべてのサービスの動作を管理するため、全体のフローが明確で管理/監視がしやすいです。
構成の認知負荷低減
ワークフローの構成や状態がシンプルです。
障害が起きた際や、ある時間の状態を知りたい場合、オーケストレーターを確認することで、全ての状態を知ることができます。
デメリット
単一障害のリスク大
オーケストレーターで各サービスの制御やエラー処理などを全て担う為、サービス数が増えると比例的に処理が多くなります。
その為、オーケストレーターを高可用性になるような設計にしていなければ、全てのサービスが停止する可能性があります。
スケーラビリティの制約強
オーケストレーター自体のスケーラビリティがシステム全体のスケーラビリティに影響を与える可能性があります。オーケストレーターの負荷が増えると、全体のパフォーマンスに影響を及ぼします。
改修コストの増加
オーケストレーター複雑なビジネスロジックを管理する場合、その実装や保守が難しくなることがあります。ビジネスロジックが頻繁に変更される場合には、オーケストレーターの改修が頻繁に必要となります。
使いどき
簡単なワークフローのサービスで集中管理をしたい時に有効かと考えます。
中央のオーケストレーターがすべてのサービスの動作を管理するため、ビジネスロジックやワークフローの定義が明確で管理しやすいです。例えば、注文プロセス全体を1つのオーケストレーターが管理し、在庫確認、支払い、配送手配を一元管理できます。
ワークフローの変更も一箇所で行えるため、簡易なシステムであれば保守性も高まるかと思います。
AWSで実装する場合
基本的にsagaパターンを実施しやすいようstepfunctionを用いて行います。
これは制御フローを整理/管理しやすいため、規模が大きくなったとしても認知負荷を軽減することができるメリット等がある為です。
- オーケストレーター(リクエストサービス)となるEC2やLambdaを用いて、SQSにリクエストを実施する。
- Lambda等を用いてSQSからポーリングし、処理を実施。
- オーケストレーターを1と2を順次実行していく
コレオグラフィ
各サービスを連鎖的に呼び出すパターンです。
デザインパターンのChain of Responsibility(責任の連鎖)と同じように連携していきます。
構成
補償トランザクションを実行する方法として、もし画像のようにBでエラーが発生した場合、再度A -> Bとエラー処理を実施します。そうすることで、実行前の状態に戻していきます。
メリット
独立性と疎結合:
オーケストレーションでは全てのサービスがオーケストレーターに依存する形でしたが、それに比べて各サービスの独立性が増しました。その為、並列処理を走らせやすかったりします。
スケーリングの影響低
疎結合なパターンのため、個々のサービスのスケーリングによって他へのパフォーマンス影響が低いです。
障害ポイントの分散
複数のサービスに対して、負荷を分散することができるため、単一障害が起こりにくくなります。
デメリット
分散されたワークフローにより複雑化
オーケストレーションと比べて、各サービスが疎結合になったことでトレーサビリティ性が低くなります。
その為、障害ポイントの調査や状態の管理が複雑化します。
各サービスの責務が増加
各サービスで補償トランザクション等のエラー処理のワークフローも必要になってきます。
オーケストレーターが担っていた責務を各サービスが保持することになるため、各サービスの実装コストが必要になってきます。
使いどき
コレオグラフィパターンは、高トラフィックを処理するためのスケーラビリティが必要な場合や、サービスの独立性と疎結合が求められるシナリオに適しているかと思います。また、頻繁にビジネスプロセスが変わる場合や、耐障害性が重要なシステム、複数のチームが並行して開発する大規模プロジェクトに有効かと考えます。オーケストレーションパターンと比べて、中央の制御が不要で、各サービスが自律的に動作するため、柔軟性とスケーラビリティが向上するからです。
AWSで実装する場合
各サービスが疎結合の為、並列で処理を実行できるパターンです。
これも補償トランザクションを実行しやすいようにstepfunctionで実施するのも有効になります。
まとめ
ビジネスのユースケースによっては、デメリットをメリットと捉えることもできますし、どちらが有効といった銀の弾丸の手法ではないです。
できるだけワークフローを簡潔にしたいか?
スケーラビリティ性やトレーサビリティ性はどうしたいか?
耐障害性や各サービスの結合度はどのようにしたいか?
そういった疑問を順番に解決していき、適材適所で各パターン使用してみてください。
参考
Discussion