Rのつく財団入り口

ITエンジニア関連の様々な話題を書いているはずのブログです。

【感想】『絵で見てわかるマイクロサービスの仕組み』【前編】

国産のマイクロサービス本!

 久々に都内に出かけたときに本屋で手に取って、絵が多くてよさそうだなと思った本。復習がてら読んでみました。マイクロサービス関連の概念やキーワードを一通り概説した本となっています。以下、要点を記した読書メモや感想です。

■第1部 マイクロサービスのアーキテクチャ

f:id:iwasiman:20210827214508p:plain
絵で見てわかるマイクロサービスの仕組み

第1章 デジタルトランスフォーメーション——マイクロサービスが求められる背景

1.1 デジタルトランスフォーメーションとは何か

  • 様々なワードが踊り見解は様々だが本質は、「ビジネスの抜本的な変革」「それにあたりビジネスの主体をITに委ねる」
  • ITシステムはバックに控えるものでなく主体となり、必要に応じて最先端のITを適用していく。

1.2 2025年の崖

  • 技術面、人材面、投資面、ビジネス面で悪影響を及ぼし経済的損失につながる。そこで...
  • インフラを標準化、コンテナで仮想化し、開発をスピードアップして構築運用も効率化
  • マイクロサービスを使ってモダン化、開発速度向上と品質向上
  • 日本だとIT技術者の7割がITベンダー側にいるので5:5ぐらいで内製化、スピーディなデリバリを

1.3 DX推進のための方策

  • ITだけでなくビジネス運用カルチャーも変革が必要。
  • トライ&エラーを許容、フェイルセーフを尊重する文化を育て、前述の技術群で柔軟でスピーディなITを。

図が多くて分かりやすいです。図の中のフォントが手書き風で、技術書の中では割と珍しい気がします。

第2章 クラウドネイティブコンピューティングとマイクロサービス

2.1 クラウドコンピューティングの歩みを振り返る

  • 2000年代初頭、SalesforceSaaSモデルのビジネスを確立した頃がクラウドの始まり。
  • WebサービスのコンセプトとしてはSOAP/WSDL/UDDIなどのプロトコルがあったが、難解で流行らなかった。
  • 2000年代なかばのWeb2.0ブームでRESTが注目され、RESTful Webサービスをインターネット上で提供するSaaSが確立。
  • その後2006年にはAWSが開始され、最初はサーバーやネットワークをクラウドに移すIaaSが注目。一旦SaaSから戻っている。
  • その後2010年頃から基盤層の上のソフトウェア層、OSやミドルウェアクラウド化するPaaSが注目。Heroku, GAE, AWS Elastic Beanstalk, Azure App Service
  • 同時にCI/CD、DevOps、アジャイル開発プロセスが注目。アプリ開発/運用のスピードアップと柔軟性の実現が大事に。
  • これら基盤構築のスピード感に合わせ、アプリ開発とメンテをタイムリーに素早く行うための設計/開発/運用手法のまとめが「マイクロサービス」。個別開発のサービスを複数組み合わせてひとつのアプリケーションを開発する。
  • 2000年代のSOAの考えから実践されていた目新しいものではない。そこにWeb2.0クラウドコンピューティング等の技術トレンドを取り入れたもの。
  • またクラウドを前提として設計構築開発運用するコンピューティングスタイルを「クラウドネイティブコンピューティング」と呼ぶ。

SOAP/WSDL/UDDI、これあの頃研究案件でやったんだよなあ...と改めて思い出しました。最初にSaaSが確立→クラウドが出てきていったんIaaSに戻る→前進してPaaSも登場→再びSaaSが脚光を浴びる、という流れは面白いですね。

2.2 クラウドネイティブコンピューティング

  • 標準仕様はないが、業界団体のCloud Native Computing Foundation(CNCF)が定義を公開している。
  • スケーラブルなアプリケーションの構築/運用。ITシステムに対し最小限の工数で頻発かつ予想通りにインパクトのある変更を加えることが目的。
  • 具体的な手法として、コンテナ、サービスメッシュ、マイクロサービス、イミュータブルインフラストラクチャ、宣言型APIがある。

github.com landscape.cncf.io

2.3 クラウドネイティブコンピューティングを支える技術要素

  • Cloud Native Trail Map が公開されている。 github.com

  • コンテナ化、コンテナオーケストレーション、マイクロサービス、DevOps(CI/CD)が中核。

  • サーバーの仮想化を実現するソリューションがコンテナ。OSは共通でその上にコンテナが載る。
  • クライドネイティブコンピューティングでは使うコンテナの数が沢山になるので、これを管理するのがコンテナオーケストレーションKubernetesデファクト
  • 開発チームと運用チームが連携してスピーディ、高頻度、確実に開発とテストリリースを進めるプラクティスがDevOps。広義になると事業計画、ユーザー体験も含まれる。本書によると全体を包括するのがDevOpsで、その中にアジャイル開発と継続的デリバリーが含まれるイメージ。
  • システム開発と運用のスピードアップと品質向上。スケーラビリティと高可用性。他のクラウドにも移動できる投資の保護。これらがクラウドネイティブコンピューティングを勧める理由。

2.4 マイクロサービスとは何か

  • サービスを組み合わせてアプリケーションを構成するソフトウェア構造がマイクロサービスアーキテクチャの中核。分散コンピューティング環境になる。
  • その周辺に技術としてコンテナ、オーケストレーション、REST、メッセージング。
  • 周辺に手法としてDevOps、アジャイル開発プロセス、CD、ドメイン駆動設計。
  • リリースはビッグバンでなくサービス単位に細かい粒度で。スケールイン/スケールアウトもサービス単位。
  • デメリットとしてサービス間の通信による遅延、分散したデータの同期問題、運用監視、サービスモデリング手法の学習コストがある。
  • 困難さもあるのにマイクロサービスを適用するのは、DXで重要なスピードと柔軟性が得られるから。

2.5 マイクロサービスの特徴

  • サービスによるコンポーネント設計:変更が容易、スケーラビリティも容易、RESTやメッセージングでサービス同士が疎結合
  • 開発/運用体制:コンウェイの法則に従える。1サービスごとに1チーム構成にできる。
  • 開発環境と永続データストアのガバナンス:サービスごとにプログラム言語やDBが違ってもよい。チームによる分散統治。
  • 基盤に対する考慮:継続的デプロイを推奨するので、品質向上。障害発生を前提にした設計を。

2.6 マイクロサービスにおける開発/運用の流れ

2.7 マイクロサービスの適用基準

  • 適用が向いていない状態を「マイクロサービスプレミアム」と呼んだりする。トレーニングが目的でないなら、小規模なシステムにはオーバースペック。大規模で複雑なシステム向け。

海外の本だと必ずしもマイクロサービス=クラウド 必須ではなく、読み進めていくとオンプレでも不可能ではなさそうだけど、事実上クラウド上でないと実現できなさそうだなあ...となります。本書ですと最初からクラウド前提、クラウドネイティブコンピューティングの中核!となっていますね。
また国産の本なので仕方ないですが、やたらDXと結び付けていてこのへんは日本企業のパワポ資料と同じ雰囲気だなあと。(弊社もです...ハイ...笑)

第3章 マイクロサービスアーキテクチャの基本

3.1 サービスの構造

  • オブジェクト指向のオブジェクトを使い、ビジネスデータはDBに保存するやり方は変わらない。
  • 多数のアプリケーションからひとつのDBを共有するような設計はマイクロサービス的ではない。

3.2 レイヤードアーキテクチャ

  • 定石の階層構造。DDDを適用するとユーザーインターフェース層/アプリケーション層/ドメイン層/インフラストラクチャ層の4つ。
  • 基盤技術の変更に弱いという弱点があり、これを解決するのに制御の逆転(IoC:Inversion of Control)という手法がある。インターフェースを使う、依存性注入のDIを使うなど。

3.3 ヘキサゴナルアーキテクチャ

  • レイヤードアーキテクチャの不得意な部分を補完し、IoCの考え方を取り入れている。マイクロサービスを始めモダンなソフトウェア設計でよく使われる。
  • 六角形の中心にドメイン層のビジネスロジックが鎮座し、マイクロサービスのサービス部分。周辺に各UIや各DBなどがあり、繋げてやりとりする実装がアダプター、ドメインにインターフェースを提供するのがポート。合わせてポート&アダプターと呼ぶ。

3.4 データベースアクセス

  • 複数のサービスが1つのDBにアクセスするような構成はマイクロサービスでは非推奨。サービスはそれぞれDBを持つ。DBの変更の影響を最小化し、他のサービスには影響しないようにする。

3.5 トランザクション管理

3.6 データベース間の同期

  • じゃあ同期はどうするの...というソリューションがSaga。あるDBへのトランザクションが成功したら次のサービスにメッセージングで成功したことを飛ばし、2番目のサービスも成功したら3番目のサービスへ飛ばし...と続く。異常が起こったら逆向きにメッセージを飛ばし、それぞれのサービスでロールバックする補償トランザクションを実施して戻していく。
  • ある時点ではDB間の同期は取れておらず、結果整合性が許容できる場合の手法なので懸念を示す人も多い。

3.7 データの結合

  • Web画面やREST経由であるサービスにアクセスすると、アプリ層から他のサービスに順番に検索をアクセス、メモリ上で1つの結果にまとめて返すのが「APIコンポジション」という手法。メモリ上に保持するのでリソースへの負担が大きい。
  • CQRS: Command Query Responsibility Segregation がコマンドクエリ責務分離。更新系と参照系を別々のサービスにし、データストアも別にするというデザインパターン。更新系はトランザクションがある信頼性の高いDB。参照系は高度な検索機能のあるデータストアを。
  • この更新系と参照系の間を埋めるのが「イベントソーシング」の考え。ビジネスデータの変更履歴を巨大なテーブルに保持し、後から非同期のメッセージングで検索用データストアに反映する。
  • CQRS&イベントソーシングを使うと、サービスのモデリング結果を素直に実装に結び付けられる。ECサイトでオーダーを更新するオーダーサービスと、オーダー履歴を検索するカスタマーサービスを別にするなど。

3.8 サービス間連携

  • RESTはよく使われるがREST限定ではない。同期型でパフォーマンスやスケーラビリティに難のあるREST以外には、非同期型のメッセージングがある。

3.9 サービス化の進め方

  • マイクロサービスアーキテクチャ自体には、開発のスピードアップの仕組みはない。1チームにドメインスペシャリスト、論理モデルを決める人、物理モデルを人を一緒に配置、ドメイン駆動設計を使いながらアジャイル開発プロセスでやるとよい。
  • 「マイクロ」サービスというネーミングでサービスの粒度は小さいほうが良いように聞こえるが、そうではない。最初は大きいサービスの粒度で初めて、後のイテレーションで小さくしていく考え方もある。
  • ステートレスな設計がモダンなソフトウェア設計では求められるが、セッションが必要な場合もある。ロードバランサーやWebアプリケーションサーバーが用意しているセッション永続化、スティッキーセッションを使うとよい。また、ステートを1つのサービスにする方法もある。後ろでDBに保持。設計に普遍性を持たせて例外を排除できる。
  • 長期に渡り既存のモノリスなシステム→マイクロサービスへの移行を続ける場合は、既存のモノリス→新サービスへの依存はよいが新サービス→既存のモノリスへの依存はだめ。

この辺りは書籍『マイクロサービスパターン』に詳しく書いてある話でした。
あちらはSagaやCQRSなど諸々の手法もマイクロサービス「パターン」の中で解説することが多かったですが、本書ですと前段としてまずマイクロサービス「アーキテクチャ」のほうで整理しています。まあこの辺は厳密な区分けはないのかなと。

第4章 マイクロサービスパターン

4.1 マイクロサービスパターン

建築用語から拝借した、先人の経験から生み出された設計を汎用化したデザインパターン。これをマイクロサービスの分野に適用したもの。Chris Richardsonさんのサイトが一番詳しい。

microservices.io

4.2 データ管理パターン

データの同期、DBの配置、分散DBでどうデータを集約するかがマイクロサービスの課題。そこでパターンが考えられた。

  • Database per serviceパターン疎結合な1サービスに1DB。RDBMSはそれぞれ違ってよく柔軟性が高い。同期、データ集約をどうするかについては別パターンを使う。
  • Shared databaseパターン:複数サービスで1つのDB共用。どうしてもトランザクションが必要だったり、既存DBを使う必要がある場合に。DB設計変更の影響が大きい。
  • Sagaパターン:複数DBの同期をとる際に、更新したことをメッセージングで伝えていく。
    • コレオグラフィ:DBと繋がったサービス群がそれぞれ自分で、メッセージング製品のトピック/キューで伝え合う。シンプルだがサービスの中にSagaのロジックが入り込む。小規模向け。
    • オーケストレーション:Sagaオーケストレーターという専用のサービスがメッセージングの仕組みとのやりとり、トランザクションの制御を受け持つ。役割分担が明確。基本はこちら。

MoM: Message Oriented Middlewareでマムではなくて「メッセージ指向ミドルウェア」という用語が本書では使われています。自分的にはあまりなじみのない用語でした。

4.3 トランザクショナルメッセージングパターン

データ処理とイベント処理は、Sagaパターンでも即時に同期をとる必要がある。この時に使う。

  • Transactional outboxパターン:ビジネスデータの更新をその都度巨大なoutboxテーブルに入れて、これをトリガーにして同期。Outboxはメールソフトの送信トレイのこと。
    • Polling publisher: このテーブルを見に行くMessage Relayの仕組みが、ポーリングで定期的に見に行って更新があったらメッセージブローカーにパブリッシュ。実装しやすい。
    • Transactional log tailing: outboxテーブルは作らずにDMのトランザクションログを見る仕組みを作る。更新があったらメッセージブローカーへ。DB製品ごとに実現方法に差がある。

4.4 サービスディスカバリパターン

クラウド上だとサービスのデプロイの都度、ドメインやIPがアドレスが変わるのでそれを把握するためのパターン。アドレスはService registryという所に格納されている。

  • Client-side discoveryパターン: クライアント側から直接Service registryに問い合わせに行く。
  • Server-side discoveryパターン: サーバー側のクラウドの境界線のあたりにいるルーター等に実装。アプリケーションコードには書かないので影響がない。
  • Service registryパターン:宛先情報を保持する永続データストア。

サービスのロケーション情報の登録手法についてもパターンあり。

  • Self Registrationパターン: デプロイ時にサービスが自分でサービスレジストリに登録しにいく。柔軟に対応できるが開発規模が大きい。
  • 3rd Party Registrationパターン:登録はサービスでなく3rdパーティのコンテナオーケストレーションツールに任せる。事実上Kubernetes

4.5 外部APIパターン

Webアプリ、SPAベース、iOS/Androidネイティブアプリ、RESTで連携...と様々な形でサービス側のAPIと連携するので、クライアントが複数、プロトコルが複数、一般インターネットはレイテンシーがあったり、何度も呼び出すと遅く実装が複雑になったりする。これを解決していくパターン。

  • API Gatewayパターンドメインの境界、クラウド側の端っこにクライアントとのやりとりを担当する専用のサービスを配置する。クライアントはこのAPI Gatewayと1回通信すればよい。API Gatewayの中で各サービスと順にアクセスして処理。GoFデザインパターンFacadeパターンと似ている。
    AWSならそのまんまAPI Gateaway、AzureだとAzure API ManagementGCPだとCloud Endpoints
  • Backend for Frontends(BFF)パターンAPI Gatewayよりさらにクラウドの端っこの境界に、PCブラウザ専用、Android専用、iOS専用、外部サービスとのAPI専用...のAPIを提供する場所を作る。多様なクライアントタイプそれぞれを個別にサポートできる。

4.6 通信パターン

通信に関するパターン。

  • Remote Proceduer Invocationパターン:リクエスト/レスポンスで同期型の通信パターン。RESTはこの実装。シンプルだが複雑で時間が掛かる処理は苦手。
  • Messagingパターン:パブリッシャー(=プロデューサー)がメッセージを投げると、一旦メッセージングの仕組みのトピック/キューに保存、サブスクライバー(=コンシューマー)に非同期に飛んでいく仕組み。一方向でもリクエスト/レスポンスも可能。同期型も非同期型も可能。

  • Domain-specific protocolパターン:特定のユースケース専用のプロトコルを運用する。メール送信のSMTP、メール受信のPOP,IMAPなど。

  • Indempotent Consumerパターン:Indempotentが「冪等性」のこと。オペレーションごとにユニークなIDを割り当て、2回以上実行されても大丈夫なようにする。たとえばメッセージングの仕組みを経由して在庫引き当てのリクエストが来ても、そのIDが処理済みなら何もしないなど。

4.7 デプロイメントパターン

Deployは元々は軍事用語で舞台や兵力を展開、配置するの意味。マイクロサービスでは分散アプリケーションである特長、スケーラビリティの確保、保守性の向上、最新技術の取り込みといった効果を得るために、デプロイについてもパターンがある。

  • Multiple service instances per Hostパターン:1つのホスト(マシン、インスタンス)に全部サービスを載せる。運用が簡単でリソースも少なく済む。例えばCPU負荷がどのサービスのせいか分からなかったり、モニタリングや耐障害性で難あり。
  • Single Service Instance per Hostパターン:1つのホストには1つのサービスしか載せない。耐障害性が向上、複雑さも軽減。コスト面が欠点。
  • Service instance per VMパターン:ハイパーバイザー型の仮想マシンにサービスを載せる。コンテナ型より低コストになることもある。たいてい重い。サービスインスタンスを分離、カプセル化できる。
  • Service instance per Containerパターン:Dockerコンテナなどの上にサービスを載せる。デプロイも高速でリソース効率もよく、Linuxならどこでも動く可搬性。最新のk8sを使ったりの保守が負担。
  • Serverless deploymentパターンパブリッククラウド提供のサーバーレスに載せる。リソース意識不要、自動スケール、リクエストごとに課金。ただしJavaだと起動まで時間が掛かったりする。イベント/リクエストベースのサービス専用で、長時間実行されるサービスには不向き。

4.8 可観測性パターン

障害に備えた監視や通知をうまくやっていくためのパターン。

  • Distributed tracingパターン:各リクエストやイベントごとに一意なIDを振る。沢山のサービスを経由してそのリクエストが処理されトレースが分散していても、IDで把握できる。
  • Log aggregationパターン:各コンテナにログやトレースが分散するので、一ヶ所に集約する。製品ではFluentd等で実装。
  • Exception trackingパターン:ログ監視中に特定キーワードを見つけたら運用担当者に自動で連絡。
  • Application metricsパターン:CPUやメモリ以外に、処理リクエスト数やレスポンスタイムなど各種メトリクス情報を収集する。k8sはこれを元にスケーリングを管理する。
  • Audit loggingパターン:ユーザ操作履歴を保存し、統計して解析することでセキュリティやコンプライアンス対応。内部犯罪を突き止めたり。
  • Health Check APIパターン:各サービスが生きているか確認用のAPIを用意。監視元はルーターロードバランサー、Service registryなどから。

4.9 リファクタリングパターン

段階的にモノリスなシステムをマイクロサービスに変えていったり、古いシステムと連携したりしていく際のパターン。

  • Anti-corruption layerパターン:腐敗防止層。サービスとモノリスの間に、通信プロトコルやアプリケーションプロトコルのギャップを埋める層を用意。たとえば新しいサービス→RESTで腐敗防止層のアダプターコンポーネント→古いシステムへSOAPで通信 など。
  • Strangler applicationパターン:多数のモノリシックなサブシステムからなる大きなシステムを、徐々にクラウドネイティブ化して侵食していく。
    全体の入口に「ストラングラーPod」というポータルメニューのようなものを配置。サブシステムが移行が終わったらすぐURLを新しい方へ変更。障害が出たらモノリスの古い方へ戻す。徐々にクラウドの木のつる植物の力で絞め殺して(strangle)、全部マイクロサービスへ移行。

【後編】に続きますよ

f:id:iwasiman:20210827214508p:plain
絵で見てわかるマイクロサービスの仕組み