マーティン・ファウラーの記事を読んで、備忘のために投稿。
これから記載する9つの原則はMicroservices
アーキテクチャで守るべき!という様な話ではなく、実際の事例の共通点を集めたに過ぎないと記事では述べられているが、成功事例に学びたいという気持ちはあるので、意識していきたい。
Microservicesの9つの原則
サービスはライブラリ単位ではなく、ドメイン単位で分割
- ドメイン単位で分割したサービスはそのサービスの関心事によってのみ変更される。リリースもまた然り。
- ライブラリ単位で分割したサービスは明示的なインターフェースを外部に示せない。ドメイン単位で分割したサービスは明示的なインターフェースを外部に示せる。それにより、カプセル化を破壊してしまう可能性を排除できる。
組織は一つのビジネスコンテキストで単一であるべき
- アプリ開発チーム、インフラチーム、DBAなど、レイヤ単位でチームを分割すべきではない。一つのビジネスコンテキストを実現するチームが全ての責任を持って、開発し、運用していくべき。
- 一つの機能を実現するまでに複数のチームが互いに連携を取るのはコストがかかる。
「プロジェクト思考」ではなく「プロダクト思考」
- プロジェクト単位でシステムを開発、運用するのではなく、プロダクト単位でシステムを開発、運用していくべき。
- 運用チームが運用を開始したときには、開発を行ったチームは解散しているなんて論外。
Smart endpoint,Dumb pipe
-
Microservices
アーキテクチャでは一つのサービスを互いに疎結合にする必要がある。 -
UNIX
で言う所のパイプの処理のようなものを目指すべき。 - サービス同士の通信も、また疎にすべき。一つのアプローチはRESTを使用した通信手段。もう一つは
RabbitMQ
などのメッセージハブを使用する方法。 - 互いにサービスを疎結合にするためにサービス単位の粒度を細かくしすぎると、通信コストの増加によるパフォーマンス低下を引き起こす。そこはトレードオフ。
分散統治
- サービスは全て一つのアプリケーションとして独立しているため、どんな技術を適用しても、そのサービスにしか変更は影響しない。つまり、そのサービスに最適な技術選定を安心して行える。
- ただし、サービス間は互いに通信を行い、ビジネス要求を満たす。そのため、新しく作ったサービスが全く違う技術で作られていたとしても、お互いに通信ができなければならない。
- この問題を解決するための一つのアプローチに
Consumer-Driven
というフレームワークが適用できる。これは二つのサービスをConsumer
とProvider
の役割に当てはめ、Consumer
で定義した形式に乗っ取ってProvider
のAPIを作成するフレームワーク。 - これにより二つのサービスを毎回結合してお互いのテストをする必要がなくなり、
Provider
はConsumer
の必要とするAPIを実現できているかを確認するテストを行えば良い。SpringだとSpring Cloud ContractがConsumer-Driven
テストフレームワークとして実装を提供している。
データの分割統治
- 複数の境界付けられたコンテキストを一つのアプリケーション内で実装している場合はよくある。これは例えば、エンドユーザ向け販売画面と売り上げ管理画面でお互いに表現されているデータが異なるといった形で現れる。
- これを適切に別のサービスに分割する方法の一つに
DDD
のコンテキストマッピングの手法があげられる。これはモノシリックなアプリケーションでもMicroservices
なアプリケーションでも有効だ。 -
Microservices
アプリケーションではこの手法をデータベースに対しても適用し、1サービスは1データベースを保有する。これにより、サービスは自分自身に最適なデータベースを選択できる。 - しかし、これは分散トランザクションを管理しなければならないという課題を生み出すことにもなる。これにはいくつもアプローチの方法はある。モノシリックなデータベース構造の維持による開発コストの削減が、データの終始完璧な一貫性よりも価値があると考えるなら、このトレードオフは十分に検討の余地がある。
インフラの自動化
- システムをできるだけ高品質に保つために自動テストを行う。
- 継続的デリバリを行う目的はデプロイプロセスを単純でつまらなくすることにある。モノシリックなアプリケーションであれ、
Microservices
なアプリケーションであれ、それは変わらない。 - モノシリックなアプリケーションと
Microservices
なアプリケーションの違いはどう継続デリバリを実現するかという方法が異なるだけ。 - 正直この原則は何を伝えたいのかよくわからなかった。。
障害設計
-
Microservices
アーキテクチャを採用し、サービスをいくつか作った場合、障害を容認する設計を行わなければならない。 - サービスを呼び出し、クライアントに対して応答を返す際にこれらの障害を容認し、ハンドリングする必要がある。これはモノシリックなアプリケーションよりも複雑な点である。
- Netflixの
Simian Army(現Chaos Monkey)
はプロダクション環境で障害を許容するテストを行う。これはモノシリックなアプリケーションでは許容できる様には思えない。 -
Microservices
アーキテクチャは機能的な監視項目(DBアクセス数など)とビジネス的な監視項目(注文数など)に重点をおく。なぜならイベント駆動であったり、複数サービスの連携であったりと突発的に起こる事象に影響されるものだからだ。 -
Microservices
アーキテクチャでは監視・ログは機能的にビジネス的に充実させておくべきである。スループット、レイテンシ、秒間あたりの注文数など。
進化的設計
-
Microservices
アーキテクチャにおける1サービスを定義つけるものの一つに、そのサービスを単体でアップグレードもしくは捨てることができるかという観点がある。 - 1サービスを長生きさせて成長させていくのではなく、サービス自体を捨てることを検討していくべき。
- サービスの交換容易性は
Microservices
アーキテクチャの重点をおく観点の一つ。ビジネス要求は変動するため、数ヶ月前に追加した機能も今では必要のない機能になっている可能性がある。そこですぐにそのサービスのみを捨てられるかどうかという点が交換容易性。