マイクロサービスのデザインパターン

第1版 2015年9月21日
第2版 2015年12月24日

Bluemixでは,たくさんのサービスやAPIが提供されており,それらを組み合わせることでアプリケーションを開発することができます.単一のプログラム言語を使って,多数のライブラリやクラスファイルを結合して作る大きなアプリケーションにももちろん利点がありますが,新しい機能やUXを継続的に提供したい時や,目的に合わせてプログラミング言語やデータベースを選択したい場合には,それぞれが独立したサービスを組み合わせるやり方が有利です.この考え方の根底にあるのが,James LewisとMartin Fowlerが提唱しているマイクロサービスです.彼らのブログ記事にあるマイクロサービスの定義にあたる部分を訳してみました.

マイクロサービス(Microservices)アーキテクチャスタイルは、それぞれが独立のプロセスで実行され,HTTPリソースAPIなどの軽量プロトコルで通信する小さなサービスを組み合わせることで,単一のアプリケーションを開発するためのアプローチです。これらのサービスは、(訳注: 技術的な観点からみた粒度ではなく)個々の業務を実現する能力に対応して構築され、完全に自動化された仕組みによって独立にデプロイ可能です。サービスの集中管理は最小限であり,異なるプログラミング言語で記述し、異なるデータストレージ技術を使用することができます.

高い注目を集めているマイクロサービスですが,ふと,サービスを組み合わせる時に有用なデザインパターンがあるのではないかと考えました.サービスの粒度をどのように考えればよいか,独立したサービスを組み上げて複雑なアプリを開発するには,それなりの周辺機能が必要ではないか.デザインパターンと言えば,Gang of Fourのデザインパターン本や,Martinが書いたPatterns of Enterprise Application Architectureが有名です.マイクロサービスに関しても,調べてみるといくつか書籍やサイトがあります(下に主なものを示します).それらを参考にまとめてみることにしました.

ここで紹介するデザインパターンです.

  • API Gateway
  • Service Registry / Service Discovery
  • Circuit Breaker
  • Polyglot Persistence
  • Command Query Responsibility Segregation (CQRS)
  • Tolerant Reader
  • Chained Services
  • Asynchronous Messaging
  • Service Instantiation
  • Consumer-Driven Contracts
  • Domain Events

API Gateway

API-Gateway

サービスやアプリを直接結合するのではなく,ゲートウェイを介して接続する.Bluemixでは,API Managementサービスが提供されている.ゲートウェイを介することで,サービス間の独立性を高めることができる.また,ゲートウェイに認証,課金,モニタリングなどの機能を持たせることで,サービスを実現したい業務能力に注力させる.それぞれのサービスは独立して開発,運用したいが,監査目的のモニタリングや課金などの機能は集約したい時には,このパターンが有効である.次に述べるService RegistryやService Discoveryと組み合わせることも可能である.前出のBluemix API Managementは,既存のサービスをAPI化する際にも有効である.マイクロサービスの考え方に沿って,複雑なアプリを構築する際には,このAPI管理の考え方が非常に重要になると思う.

Service Registry / Service Discovery

ServiceRegistry

サービス同士が直接つながるのではなく,サービスをService Registryに登録し,Service Registryを用いた発見,結合を行う.対象となるサービスが少数である場合には,登録・発券の機能は必要ではないが,サービスやAPIが多数ある場合や,企業,あるいは業界内で,サービス提供元が異なるサービスが多い場合には,必要なパターンとなる.Bluemixでは,API Harmonyサービスが,サービスの類似検索や推薦を行う.

Circuit Breaker

CircuitBreaker

分散されたサービスの呼び出しにおいて提供サービスが失敗しているに関わらずサービス呼び出しを続けると,計算リソースの枯竭を招き,システム全体の性能低下を招く.サービスと呼び出し側のクライアントの間にCircuit Breakerを置いて,サービスから一定回数以上正常な結果が得られない場合に,失敗するサービスの呼び出しをバイパスする.このパターンによって正常状態が維持されるのではなく,システム全体が正常に復帰するには,全てのサービスが復活する必要があることに注意する.

Polyglot Persistence

PolyglotPersistence

目的に応じてプログラミング言語を使い分けるPolyglot Programmingパターンのデータベース版.それぞれのサービスが,それぞれの用途に応じてRDBやNoSQLを用いる.それぞれのサービスが,独立してデータベースとデータスキーマを持つことは,サービスの独立性を確かに高める.しかし,複数のサービスが,同じデータベースを参照したい,データベース間で同期をとりたいという要求もあるだろう.データ参照・更新機能をAPI化(カプセル化)し,複数のサービスから呼び出すことでデータベーススキーマへの依存性を低減させる,同じデータベースでもスキーマを分離し独立性を高めるなどの手法が現実的には考えられる.Bluemixにおいては,関係データベース,NoSQL DB,オブジェクトデータベース取り混ぜて多数のデータベースサービスを提供している.

Command Query Responsibility Segregation (CQRS)

CQRS

データを照会するサービスと更新を行うサービスを分離することで副作用を最小化する.データ更新処理は,照会よりも重いロジック (検証やセキュリティなど)
が必要であり,両者を分けることで照会には必要とされない複雑さを抑制できる.サービス呼び出し側に対してはGatewayサービスが相対しても良い.上述のPolyglot Persistenceパターンでも述べたように,データベースへのアクセス機能をサービス化することで,CQRSは実現可能である.ただし,マイクロサービスにおけるサービス分割の粒度は技術的な要因でなく,ビジネスを実現する業務機能の観点から定義されることが原則であり,なかなかに奥が深い.

Tolerant Reader

TolerantReader

複数のサー ビスを定義してそれらを疎結合するのがマイクロサービスの特徴であるが,結果として,サービス間の通信が課題となる.プログラムコードの更新に対して耐性を持ったデータ読み込みのパターンである.“送信するものに関しては 厳密に、受信するものに関しては寛容に.”は,計算機科学者Jon PostelがTCPを規定する際に提案した原理であるが,マイクロサービス間の通信のおける原理としてもあ成り立つ.サービスはREST APIで提供され,データはJSON形式であることが多い.JSON Schemaは存在するが一般的に使われているわけではないので,交換されるデータがどのような形式をしているかについては,サービス間での何らかの合意が必要である.更に,APIのバージョニングも大きな課題であるが,これについてはあま り有効なパターンがないようだ.

Chained Services

ChainedService

サービスが順列に接続し通信を行う.マイクロサービスの特徴である“Dumb pipe”のパターンである.UNIX Pipeと違って分岐を許す.マイクロサービスの結合そのものをコントロールする共通の仕組みは現在知られていない.”Dumb pipe”に代表されるマイクロサービスの原理によれば,中央集権的にサービズの振る舞いを管理することは望ましくないが,さりとて,サービスの結合を表現する仕組みは必要なのではないかと個人的には思う.ちなみに,オーケストレーション(中央集権)とコレオグラフィ(非集中)はマイクロサービスの明確に区別される.

Asynchronous Messaging

async

複数のサービスがメッセージングサービス(queue)を共有する.サービスの独立性,非同期性を保つためよく使われる.反面,サービス間の呼び出しに順 序がある場合に,全体のロジックを記述しにくい.また,Queueが単一故障点になる可能性がある.Bluemixでは,IoT Foundationがこのパターンを実現するサービスである.

Bulkhead

bulkhead

システム障害を局所化するために,同じシステムを複数用意し,それぞれを障壁を用いて孤立化しておく.障壁とは,データセンター単位,VM単位,コンテナ単位などが考えられる.

Service Instantiation

サービスをどのレベルでinstantiateするかについては複数の選択肢がありえる.

  • Multiple service instances per host
  • Single service instance per host
  • Service instance per VM
  • Service instance per Container

Consumer-Driven Contracts

通常1対多となるサービスの提供者と消費者間でのサービス契約において,消費者が,提供者のサービス全体ではなく,必要な部分のみを「期待」 (expectation)として提供者側に提示することで,提供サービスの更新への耐性を向上させ,サービスやビジネスの価値を高めることができる.

Domain Events

サービス同士をメッセージングを用いて結合する際に,単一のメッセージング基盤を用いるのではなく,2つのサービス(のみ)をキューサービスで繋ぎ,分散型コレオグラフフィーを行うパターン.

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中