"Microservices"を読んだ

Sep 10, 2014

James Lewis氏とMartin Fowler氏による"Microservices"を読んだ.以前ざっと目を通したが,最近よく耳にするようになったのでちゃんと読んだ.以下はそのメモ.

概要

  • "Microservices" とはソフトウェアシステムの開発スタイルである
  • Microservice は一連の小さなサービスで 1 つのアプリケーションを開発する手法
    • それぞれのサービスは自身のプロセスで動いており,軽量な機構(e.g., HTTP API)を通じて情報をやりとりする
    • これらのサービスは独立して自動デプロイされる
  • 一枚岩として構築される Monolithic スタイルのアプリケーションと比較すると分かりやすい
    • 一般的なエンタープライズのアプリケーションは,クライアントサイドのユーザインターフェース,データベース,サーバーサイドのアプリケーションの 3 つで構成される
    • サーバーサイドのアプリケーションは,HTTP リクエストを受け,データベースとやりとりし,クライアントに HTML を返す
      • このようなサーバーサイドアプリケーションは Monolithic であり,システムへの変更は新しいバージョンのアプリケーションのビルドとデプロイを要する
  • Monolithic システムの構築は一般的には成功したスタイルである
    • リクエストを処理するロジックは単一のプロセスで動く
    • ロードバランサを配置しスケールアウトさせることもできる
  • クラウドに多くのアプリケーションがデプロイされ始めると Monolithic アプリケーションはフラストレーションになってきた
    • システムの変更サイクルは,全て結びついている
    • モジュール構造の維持や影響範囲の限定が困難になる
    • アプリケーションの一部だけスケールが必要なのに全体をスケールしなければならない
  • これらのフラストレーションが Microservices アーキテクチャーを導きだした,Monolithic なアプリケーションと比較して Microservices は:
    • 独立してデプロイできる
    • 独立してスケールできる
    • しっかりしたモジュールの境界をもつ(影響範囲の限定)
    • 様々なプログラミング言語を利用できる
    • 異なるチームで運用できる
  • Microservices は新しい考え方ではない
    • 少なくともその根源は UNIX のデザイン哲学に立ち戻っている

Microservice の特徴

  • 正式な定義はないが,共通の特徴を述べる
    • すべての Microservices が全ての特徴を満たすわけではない

サービスによるコンポーネント化

  • コンポーネントを組み合わせてシステムを作りたい
  • コンポーネントを入れ替え可能/アップグレード可能な独立したソフトウェアと定義する
  • Microservices はライブラリを使うが,主要なコンポーネント化はサービスへ分割することで行う
    • ライブラリを 1 つのプログラム内で連結し,インメモリーで関数呼び出しを行うコンポーネントと定義する
    • サービスを別プロセス動作し,HTTP リクエストや RPC などで連携するコンポーネントと定義する
  • サービスをコンポーネントとして扱う主要な理由の 1 つは独立してデプロイできること
    • 良い Microservices アーキテクチャーはサービス間をなるべく粗結合にして,変更時のデプロイを少なくする
  • サービスをコンポーネントとして扱うとインターフェースがより明確になる
  • プロセス内のコールと比べてリモートのコールはコストが高いので API はなるべく粗くある必要がある

ビジネス能力に基づく組織化

  • 巨大なアプリケーションを分割するとき普通は技術レイヤーでそれを区切る(
    • e.g., UI チーム,サーバーサイドチーム,データベースチーム
    • このようなチーム分割は,単純な変更を加えるだけでも際もチーム間の調整や予算承認が必要になる
    • コンウェイの法則 - Strategic Choice
  • Microservices はビジネス能力に基づきサービスの分割を行う(
    • このようなサービスは,そのビジネス分野に対して UI やデータストレージ,外部連携といった幅広いスタックの実装が必要になる
    • 結果として,チームには UX からデータベース,プロジェクト管理といったフルスタックな開発スキルが要求される
  • Micorservices の適切な粒度は?
    • 1 サービスに数十人が参加している場合もあれば,1 人で 1 サービスという例もある

プロジェクトではなくプロダクト

  • ほとんどのアプリケーション開発はプロジェクトとして管理され,機能の一部がデプロイされて完遂する
    • 完遂するとソフトウェアはメンテナンスチームに引き渡されて,プロジェクトチームは解散する
  • Microservices では,チームはプロダクトを持っていると意識する
    • これは Amazon の"you build, you run it"の考え方に影響を受けている
    • 開発者は常にプロダクションのソフトウェアの挙動やそれを利用するユーザのことを意識するようになる
  • プロダクトとして考えることはそのビジネス能力について考えることにもなる
    • ソフトウェアを 1 つ 1 つが完遂するべき機能の集まりとしてではなく,ソフトウェアによりビジネス能力をいかに強化するかを継続して考えることになる

スマートなエンドポイントと単純なパイプ

  • Microservices アプリケーションは,出来るだけ粗結合であることを目的にする
    • それぞれが独自のドメインロジックを持っていて UNIX のフィルターのように動作する
      • リクエストを受けて,適切なロジックを実行して,レスポンスを返す
    • BPEL や WS-Choreography のような複雑なプロトコルではなく,REST 的な単純なプロトコルを用いる
  • HTTP API が用いられる
    • Microservices チームは World wide web に上に作られた原則やプロトコルを使う
  • 軽量なメッセージングプロトコルも用いられる
    • RabbitMQ や ZeroMQ など
  • Monolithic アプリケーションではメッセージのやりとりはインメモリーのメソッドの実行や関数呼び出しで行われる
    • Monolithic から Microservice への移行ではパフォーマンスの低下が問題になる
    • 密なコミュニーションを粗めなコミュニーションと入れ替える必要がある

分散ガバナンス

  • 中央政権的ガバナンスは単一の技術への統一へ向かう傾向がある
    • この手法は行き詰まる
    • 全ての問題が釘でそれに対する全ての解法がハンマーであるわけではない
  • Microservices は適切な場所で適切なツールを使うことを好む
    • Standup の簡単なレポートページを作るのに Node.js を使っても良いし,リアルタイム性を求められる部分に C++を使っても良い
    • データベースも好きに選んでも良い
  • "できる"であって"すべき"ではない,選択肢があるということ
  • 分散ガバナンスの頂点は,Amazon により有名になった"build it / run it"精神かもしれない
    • チームは運用を含め,構築したソフトウェア全ての側面に責任をもつ
    • このレベルの権限の委譲は普通のことではないが多くの企業が開発チームに多くの責任を与え始めている
    • 毎晩 3 時に起こされるとなると,コード書くときの質により集中するようになる

分散データ管理

  • データ管理を分散させる方法は多く存在する
    • 抽象的なレベルで言うと,それはシステム間で現実世界の概念モデルが異なることを意味する
    • これは大きなエンタープライズ間の統合を行う時の共通の問題である
      • セールスから見た"customer"とサポートから見た"customer"は異なる
  • この問題はアプリケーション間でも共通である
    • ドメイン駆動開発の"境界づけられたコンテキスト"で考えると良い
      • ドメイン駆動開発は,複雑なドメインを複数の境界づけられたコンテキストに分割し,それらの関係性をマップする(
  • Microservices はそれぞれのサービスがそれぞれデータベースを管理することを好む
    • Monolithic アプリケーションは一貫したデータの為に単一のデータベースを用いるのを好む
  • データの分散管理は更新管理に影響を与える
    • 複数のリソースを更新する際,一般的には,一貫性を保つためにトランザクションを用いる
    • この方法は,Monolithic アプリケーションでも行われる
  • このようなトランザクション処理は,一時的にサービス同士を結びつけることになる

インフラの自動化

  • Microservices アプリケーションは,継続的デリバリーや継続的インテグレーションの経験をもつチームによって構築されている
    • このようなチームはインフラの自動化も行っている
    • ビルドパイプラインを作る(
  • ソフトウェアがちゃんと動作することを確認するために,十分な自動テストを行う
    • そして新しい環境へ自動デプロイも行う

障害設計

  • サービスをコンポーネントとして扱うため,アプリケーションはサービスの障害に耐性のあるように設計される必要がある
    • サービスへのリクエストは失敗する可能性があるので,クライアントは出来る限り正常にこれに対応しなければならない
    • Microservices チームはどのようにサービス障害が UX に影響を与えるかを常に考慮する
    • Netflix のSimian Armyは,営業日であっても障害を誘発してアプリケーションの復旧とモニタリングをテストしている
  • サービス障害はいつでも発生するので,いち早く障害を検知し,可能であれば自動で復旧させることが重要である
    • Microservices はリアルタイムのモニタリングを重用視する
      • アーキテクチャー要素の監視(データベースが秒間どれだけのリクエストを受けているか)
      • ビジネスに関連したメトリクスの監視(分間どれだけの注文が発生したか)

進化的設計

  • サービスの分割により開発者は変化のスピードを落とすことなく変更をコントロールできる
  • コンポーネント化するときどのように分割するのがよいか迷う
    • 独立して交換可能か,アップグレード可能かが重要
      • 他のコンポーネントに影響を与えることなく,コンポーネントを書き換えられるか
    • 多くの Microservices チームはサービスを長期間で進化させるより,廃棄されることを期待している
  • The Guardianのウェブサイトは Monolithic として設計されつつ,Microservices 舵をきったよい例
    • まだ Monolithic アプリケーションがコアであるが,新機能の追加には,Monolithic アプリケーションの API を使って Microservices により構築されている
    • この手法は,そもそも一時的な機能に追加するときに便利
    • そのようなウェブサイトの一部は開発速度の速い言語で構築され,簡単に統合することができるし,イベントが終了したらすぐに切り離すこともできる
  • コンポーネント化するとより粗めのリリーススケジュールが立てられる
    • Monolithic アプリケーションでは,変更した際にアプリケーション全体をビルドし直してでプロイする必要があるが,Microservices では,変更を加えたサービスのみをデプロイし直せばよい
      • これはリリースのスピードを早める
    • 悪い点としてサービスの利用者に影響を与える
      • 伝統的な手法では,バージョニングによりこれを解決してきたが,Microservices ではそれを最後の手段にする
        • サプライヤーの変化に対して出来る限り耐性を持つようにデザインすれば多くのバージョニングを避けることができる

Microservices は未来か?

  • Microservices アプリケーションの先駆者としては,Amazon や Netflix,The Guardian,UK Government Digital Service などが挙げられる
  • Microservices は経験的に良い結果が出ているが, 将来のソフトウェアアーキテクチャーの進むべき方向であるかは確証はない
  • Microservices はまだ十分に成熟していない
    • コンポーネントの境界をどこにするか決めるのは難しい
    • サービスの境界を超えたコードの移行は難しい
    • インターフェースの変更が大変
    • 後方互換を保つ必要がある
    • テストが複雑になる
    • 高いスキルが求められる
  • Microservices アーキテクチャーから始めるべきではない
    • Monolithic で初めて,モジュール性を保ち,問題になればそれを Microservices として分割するのが良い

参考

英語

日本語