マイクロサービスアーキテクチャ 第2版

  • オライリー・ジャパン (2022年12月2日発売)
4.33
  • (3)
  • (2)
  • (1)
  • (0)
  • (0)
本棚登録 : 122
感想 : 5
4

1章 マイクロサービスとは
 独立デプロイ可能性を保証するには、マイクロサービスを必ず「疎結合」にする必要があります。他のサービスを変更せずに、あるサービスを変更できなければなりません。これは、サービス間に明確に定義された安定した契約が必要であることを意味します。いくつかの実装上の選択が、これを困難にします。例えば、データベースの共有は特に問題です。
 独立デプロイ可能性自体に、非常に価値があることは明らかです。しかし、独立デプロイ可能性を実現するには、他の多くのことを正しく理解する必要があり、それらには利点があります。独立デプロイ可能性を強制することに注目していることがわかるでしょう。結果としての独立デプロイ可能性に着目することで、多くの付随的な利点を得ることができます。
 安定したインタフェースを備えた疎結合のサービスを目指すことは、最初にマイクロサービス境界をどのように見つけるかについての、我々の考えの指針となります。

■マイクロサービスの利点
・技術の異種性
 連携する複数のマイクロサービスで構成されるシステムでは、サービスごとに異なる技術を使う判断ができます。これにより、最終的に最大公約数的になることが多い、標準的で画一化されたアプローチではなく、実装ごとに適したツールを選択できます。
 システムのある部分でパフォーマンスを向上させる必要がある場合、要求されるパフォーマンス水準を達成するために別の技術スタックを使う、という判断をすることもあるでしょう。また、システムの別の部分では、データの格納方法を変える必要がある、と判断することもあるでしょう。例えば、SNSでは、ユーザ対話をグラフ指向データベースに格納し、ソーシャルグラフの高度な相互接続性を反映する一方で、ユーザの投稿をドキュメント指向データストアに格納し、図1-10に示すような異種アーキテクチャを生み出すかもしれません。
・堅牢性
・スケーリング
・デプロイの容易性
・組織との連携
・合成可能性

■マイクロサービスの課題
・開発者体験
・技術の過負荷
・コスト
・レポート
・監視とトラブルシューティング
・セキュリティ
・テスト
・遅延
・データ一貫性

■まとめ
 マイクロサービスアーキテクチャは、技術選択、堅牢性とスケーリングへの対処、チーム編成などにおいて、非常に高い柔軟性を与えてくれます。この柔軟性は、多くの人をがマイクロサービスを採用する理由の1つです。しかし、マイクロサービスには大きな複雑さも伴うので、この複雑さが正当であることを確認しなければなりません。多くの人々にとって、マイクロサービスはデフォルトのシステムアーキテクチャとなっており、事業上あらゆる状況で使われています。しかし、マイクロサービスはアーキテクチャ上の択肢の1つであり、解決したい問題によって、その使用が正当化される必要があると考えています。多くの場合、より簡単なアプローチほど、ずっと容易にソフトウェアをデリバリできます。
 とはいえ、多くの組織、特に大規模組織は、マイクロサービスがいかに効果的になり得るかを示しています。マイクロサービスの中心的な概念を正しく理解して実装すると、システムが部分の総和を超えるような、強力で生産性の高いアーキテクチャを構築するのに役立ちます。
 本章が、これらの概念の優れた入門となっていることを願っています。次に、マイクロサービス境界をどのように定義するかを検討し、その過程で構造化プログラミングやドメイン駆動設計について探ります。


2章 マイクロサービスのモデル化
■マイクロサービス向けのドメイン駆動設計 (DDD) の例
 ここまで、マイクロサービスの状況でドメイン駆動設計がどのように機能するかを探ってきました。このアプローチがどのように役立つかを、まとめてみましょう。まず、ドメイン駆動設計が強力である主な要因は、(ドメイン駆動設計にとって非常に重要な)境界づけられたコンテキストが、明示的に情報隠蔽に関するものであることです。より幅広いシステムに対して明確な境界を提示しつつ、システムの他の部分に影響を与えずに変更できる内部の複雑さを隠蔽します。つまり、ドメイン駆動設計のアプローチに従うと、それを認識しているかどうかにかかわらず、情報隠蔽を採用していることになります。また、以前説明したように、これは、安定したマイクロサービス境界を見つけるのに不可欠です。
 第二に、共通のユビキタス言語の定義に重点を置くことは、マイクロサービスエンドポイントを定義する際に、非常に役立ちます。ユビキタス言語は、APIやイベント形式などを考える際に利用するための、共有ボキャブラリを提供します。また、ユビキタス言語は、言語が境界づけられたコンテキスト内で変更されることを許すか(境界自体に影響を与える、境界内での変更)という観点で、APIの標準化をどこまで進める必要があるか、という問題の解決にも役立ちます。

■まとめ
 本章では、何が良いマイクロサービス境界になるか、そして、問題領域において、疎結合と高凝集の両方の利点を得られる接合部を探す方法について、学ぶことができたでしょう。ドメインを詳しく理解することは、このような接合部を探すのに不可欠です。そして、マイクロサービスをそのような境界に合わせることで、結果として得られるシステムで、マイクロサービスの利点を受けられる可能性が高くなるでしょう。また、マイクロサービスをさらに分割する上でのヒントも、示しました。
 Eric EvansのDomain-Driven Design で紹介されているアイデアは、サービスの適切な境界を見つけるのに非常に有用です。本章では、そのほんのさわりを紹介しただけですが、Ericの書籍では、より詳細に踏み込んでいます。さらに詳しく知りたければ、Vaughn Vernon の Implementing Domain-Driven Designを勧めます。このアプローチの実用性を理解することができるでしょう。より簡潔な書籍の方がよければ、Vernonの Domain-Driven Design Distilledを勧めます。素晴らしい要約です。

3章 モノリスの分割
 要するに、モノリシックアーキテクチャからマイクロサービスアーキテクチャに機能を移行する作業に着手する際は、「何」を達成したいのかを明確に理解する必要があります。この目標が作業を進める姿勢を形作り、正しい方向に進んでいるかを判断することもできるでしょう。
 移行を漸進的に行うべきです。変更を加え、その変更をロールアウトし、評価を行い、再び繰り返します。1つのマイクロサービスの分割でさえも、一連の小さな手順に分割することができるのです。
 本章の概念をもっと詳しく調べたいのならば、このトピックを深く掘り下げている私の別の著書 Monolith to Microservices*1を勧めます。
 本章の大部分は、やや高水準な概要になっています。しかし、次の4章では、マイクロサービスがどのように互いに通信するかを調べるなど、より技術的な内容となっていきます。


4章 マイクロサービスの通信スタイル
■まとめ
 本章では、マイクロサービスの通信の主なスタイルのいくつかを分析し、さまざまなトレードオフを説明しました。「正しい」選択肢は1つとは限りませんが、同期、非同期呼び出し、イベント駆動、リクエスト/レスポンスの通信スタイルについて、読者の状況に適した正しい選択を行う上で参考になる情報を、詳しく説明できたと思います。私が非同期イベント駆動連携に先入観があるのは、経験からだけでなく、結合全般への嫌悪感からでもあります。イベント駆動の通信スタイルには無視できないほどに大幅な複雑さが伴い、すべての状況は固有のものです。
 本章では、このような対話スタイルの実装に使える、いくつかの具体的な技術について簡単に触れました。これで、本書の第Ⅱ部に入る準備が整いました。いよいよ実装です。次の5章では、マイクロサービスの通信の実装について、より深く探っていきます。


5章 マイクロサービスの通信の実装
 クライアントがサービスを利用する際に、できるだけ柔軟であろうとする例は、(「ロバストネス原則」、「堅牢性原則」としても知られる)ポステルの法則(https://oreil.ly/GVqeI)を示しています。ポステルの法則は、「送信するものに関しては厳密に、受信すあるものに関しては寛容に」というものです。この格言のもともとの状況は、ネットワークを介したデバイスの対話です。そこでは、あらゆる種類の奇妙な出来事が起こることを、想定すべきです。マイクロサービスベースの対話の状況では、この法則は、ペイロードの変更に対して耐性があるような形でクライアントコードを構築するように、我々を導きます。

 効果的なマイクロサービスアーキテクチャの秘訣の1つは、コンシューマファーストのアプローチを受け入れることだと、覚えておきましょう。マイクロサービスは、コンシューマに呼び出されるためにあります。コンシューマのニーズが最優先であり、上流コンシューマに問題が引き起こすような変更をマイクロサービスに行う場合、このことを考慮する必要があります。
 もちろん状況によっては、コンシューマを変更できないこともあるでしょう。Netflixでは、(少なくとも以前は)Netflix APIの旧バージョンを使う古いセットトップボックスに関する問題があったと、聞いたことがあります。このセットトップボックスは簡単にはアップグレードできないので、サポートを無効にできるレベルにまで古いセットトップボックスの数が減らない限り、古いエンドポイントを利用可能にしておく必要があります。古いコンシューマによるエンドポイントへのアクセスを停止するという判断は、最終的に財務上の判断となる場合があります。旧インタフェースをサポートするコスト、そのコンシューマから得られる利益を、天秤にかけるのです。

■まとめ
本章では、多くのことを取り上げました。 その一部をまとめます。
・まず、解決したい問紙に基づいて、技術を況と好みの通信スタイルに基づいて、最も適切な技術を選択する。先に技術を選ぶという罠に陥らない。(まず4章で紹介し、図5-10に再び示した)マイクロサービス間の通信スタイルのまとめは、意思決定の指針となるが、このモデルに従うだけでは、自分自身の状況を慎重に考えることの代わりにはならない。

・何を選択するにせよ、スキーマの利用を検討する。契約を明確にするだけでなく、偶発的な破壊的変更を検出する上でも有効である。
・可能な限り、後方互換性のある変更を行い、独立デプロイ可能性を維持するようにする。
・後方互換性のない変更をしなければならない場合、 コンシューマにアップグレードする時間を与え、ロックステップデプロイを回避する方法を探す。
・エンドポイントに関する情報を人にわかるようにするために、何ができるかを考える。人向けのレジストリなどの利用を検討し、混沌の解明に役立てる。

 本章では、2つのマイクロサービス間の呼び出しを実行する方法を見てきましたが、複数のマイクロサービス間で操作を調整する必要がある場合は、どうなりますか。次の6章では、それが焦点となります。


6章 ワークフロー
■ロールバックを減らすために、ワークフローの手順を並べ替える

■まとめ
 このように、マイクロサービスアーキテクチャでワークフローを実装するには、実装したいビジネスプロセスを明示的にモデル化することに行き着きます。これは、ビジネスドメインの特性をマイクロサービスアーキテクチャでモデル化する、という考え方に戻ります。マイクロサービスの境界が主にビジネスドメインの観点から定義されている場合ビジネスプロセスを明示的にモデル化することは、理にかなっています。
 オーケストレーション、コレオグラフィのどちらに魅力を感じるとしても、どのモデルが自分の問題領域に適しているのか、よりよく理解できるようになることを願っています。 この分野をさらに詳しく調べたい場合、 サーガを明示的にカバーしていませんが、Gregor Hohpe, Bobby Woolf による Enterprise Integration Patterns が、 各種のワークフローを実装する際に非常に役立つパターンを多数紹介しています*1。また、 Bernd Ruecker の Practical Process Automation も、心から勧めます*2。 Berndの書籍はオーケストレーションベースのサーガに大きな重点を置いていますが、このトピックについてこれから必要となる有益な情報が満載です。これで、マイクロサービスがどのように互いに通信、連携するかがわかりましたが、そもそもどのように構築しますか。次の7章では、マイクロサービスアーキテクチャの状況で、ソース管理、継続的インテグレーション、継続的デリバリを適用する方法を見ていきます。


7章 ビルド
■本当にCIを行っているか
・1日1回、メインラインにチェックしているか
・変更を検証するためのテストスイートがあるか
・ビルドが壊れたとき、その修正がチームの最優先事項であるか

■継続的デリバリと継続的デプロイの比較
「継続的デリバリ」(Continuous Delivery)、「継続的デプロイ」(Continuous Deployment)という用語に混乱しているのを、時々見かけます。すでに説明したように、継続的デリバリは、各チェックインをリリース候補として扱う概念であり、各リリース候補の品質を評価し、デプロイできる状態かを判断します。一方、継続デプロイでは、各チェックインを自動化メカニズム(例えばテスト)を使って検証する必要があり、その検証チェックを通過したソフトウェアは、人の介入なしに自動的にデプロイされます。そのため、継続的デプロイは、継続的デリバリの拡張と考えることができます。継続的デリバリがないと、継続的デプロイを行うことはできません。しかし、継続的デプロイを行わなくても、継続的デリバリを行うことは可能です。
 継続的デプロイは、万人向けではありません。多くの人は、人を介入させ、ソフトウェアをデプロイすべきかを判断したいと考えます。これは、継続的デリバリと相性がいいものです。しかし、継続的デリバリを採用することは、本番環境へのデプロイまでの最適化を、継続的に注視することを意味します。可視性が高まるため、どこで最適化すべきかを確認しやすくなります。多くの場合、チェックイン後のプロセスにおける人の関与は、対応が必要なボトルネックとなります。手動の回帰テストから自動化された機能テストへの移行が、その例です。結果として、ビルド、デプロイ、リリースプロセスの自動化が進むにつれ、継続的デプロイに近づいていることに気付くでしょう。

■まとめ
 本章では、マイクロサービスを最終的に使うことになるかどうかに関係なく、あなたに大いに役立つであろう、いくつかの重要なアイデアについて説明しました。継続的デリパリからトランクベース開発、モノリポ、マルチリポまで、これらのアイデアには、調べるべき側面がたくさんあります。多くのリソースと参考資料を示しましたが、深く調べることが重要な、次のテーマに進むべきときが来ました。そのテーマは、デプロイです。


8章 デプロイ
■まとめ
 さて、本章では多くのことを説明しました。先に進む前に、簡単にまとめておきましょう。まず、先ほど説明したデプロイの原則を思い出してください。
・分離された実行
 (独自のコンピューティングリソースを持ち、その実行が近くで動作する他のマイクロサービスインスタンスに影響を与えることができないような)分離された方法で、マイクロサービスインスタンスを実行する。
・自動化の重視
 高度な自動化が可能な技術を選択することに重点を置き、文化の中核として自動化を採用する。
・IaC (Infrastructure as Code: コードとしてのインフラ)
 自動化を容易にし、情報共有を促進するために、インフラの構成を表現する。環境の再作成を可能にするために、このコードをソース管理に保存する。
・停止時間のないデプロイ
 独立デプロイ可能性をさらに進め、サービスのユーザ(人、他のマイクロサービス)の停止時間なしで、マイクロサービスの新バージョンのデプロイを実行できるようにする。
・望ましい状態の管理
 マイクロサービスを定義された状態に維持するプラットフォームを使い、停止やトラフィック増加が発生した場合に、必要に応じて新しいインスタンスを起動する。

 さらに、適切なデプロイプラットフォームを選択するための、私なりの指を紹介しました。
1. 壊れていないなら、 修正しない。
2. 自分が満足できる範囲で、制御を手放す。それから、さらにもう少しだけ、制御を手放す。すべての作業を、Herokuのような優れたPaaS (あるいはFaaS プラットフォーム)に任せられるなら、任せて満足する。本当に、最後の設定までいじる必要があるか。
3. マイクロサービスのコンテナ化には苦痛も伴うが、分離のコストを考えると、非常に優れた妥協点であり、ローカル開発にとっていくつかの素晴らしい利点があり、何が起こるかをある程度制御できる。将来は、Kubernetesに期待する。

また、「自分の」要件を理解することも重要です。Kubernetesは、あなたにうまく合うかもしれませんが、おそらくもっと単純なものでも、同じようにうまくいくでしょう。より単純なソリューションを選ぶことを、恥ずかしく思う必要はありません。また、作業を他の誰かに任せることを、あまり心配する必要はありません。作業をパブリッククラウドに任せられる場合、私なら任せるでしょう。自分の作業に専念できるからです。
 そして何より、この分野は多くの変化の中にいます。この分野の主要な技術に対する知見を提供でき、現在話題の新技術よりも長く使うであろう原則も共有できたなら、辛いです。次に何が起こっても、あなたにはそれを受け止める準備が整っていることでしょう。
  次の9章では、この章で簡単に触れた話題、つまり、 マイクロサービスが実際に動作することを確認するテストについて、 さらに詳しく探ります。


9章 テスト
 一般的に言えば、テストの目的は、ソフトウェアの品質が十分であるかどうかに関するフィードバックを得ることです。理想的には、できるだけ早くフィードバックを得て、エンドユーザが問題に遭遇する前に、ソフトウェアに問題があるかどうかを特定したいところです。そのために、ソフトウェアをリリースする前に、多くのテストを実施するのです。
 しかし、テストを本番前環境のみに限定することは、我々の足枷となってしまいます。問題を発見できる場所を減らし、最も重要な場所、つまりソフトウェアが実際に使われある場所で、ソフトウェアの品質をテストする可能性を排除することになってしまいます。
 我々は、本番環境でもテストを実施できますし、実施すべきです。本番環境でのテストは、安全な方法で行うことができるものであり、本番前環境でのテストより高品質のフィードバックを得られます。また、この後説明するように、あなたがそれに気付いているかどうかわかりませんが、あなたは、本番環境でのテストをすでに行っていることでしょう。

■まとめ
 本章では、テストに対する全体的なアプローチについて説明しました。これが、自分のシステムをテストする際の一般的な指針となることを願っています。もう一度、基本をおさらいしておきましょう。
・高速なフィードバックを得られるように最適化し、それに応じてテストの種類を分ける。
・複数チームにわたるエンドツーエンドテストが必要ないようにする。 代わりに、コンシューマ駆動契約 (CDC) の使用を検討する。
・チーム間の会話の論点を提供するために、 CDCを使用する。
・テストより多くの労力を費やすこと(MTBFの最適化)、本番環境で迅速に問題を検出すること(MTTRの最適化)の間のトレードオフを理解する。
・本番環境でのテストを試す。

 テストに関するさらに詳しい書籍として、 Lisa Crispin Janet Gregory による Agile Testingを勧めます。この書籍は、特にテストの4象限の使い方を詳しく取り上げています。テストピラミッドの詳細、コード例、さらに多くのツールのリファレンスには、 Ham Vocke の 「The Practical Test Pyramid」も勧めます。
 本章では、本番環境に進む前にコードが正しく動作するか確認することに、主に重点を置きましたが、本番環境に進んだ後のアプリケーションのテストについても、検討を開始しました。こうしたテストを、さらに詳しく調べる必要があります。マイクロサービスは、本番環境でソフトウェアがどのように振る舞うかを理解する上で、多くの問題を引き起こすことがわかりました。次の10章では、この話題を深く掘り下げます。


10章 監視から可観測性へ
 分散システムを理解するのは複雑であり、分数が進むほど、本番環境のトラブルシューティングが難しくなります。プレッシャーがかかり、アラートが鳴り響き、顧客が悲鳴を上げているときは、正しい情報を入手し、一体何が起こっているのか、正するには何をすべきなのかを理解することが重要です。
 マイクロサービスアーキテクチャが複雑になるにつれ、どのような問題が発生する可能性があるかを事前に知ることが、難しくなります。それどころか、遭遇する問題の種類に頻繁に驚くことになります。したがって、(受動的な)監視活動から、能動的にシステムの観測性を高める方向に、思考を変化させることが不可欠となります。これには、ツールの変更だけでなく、静的なダッシュボードからより動的な分析活動に変化させる必要もあります。
 単純なシステムでは、基本的なことが大きな進歩になります。最初からログ集約を行い、ログ行で相関IDも取得します。分散トレーシングを後で追加することができますが、 実施するタイミングに注意する必要があります。
 システム、マイクロサービスの正常性に対する理解を、「満足」または「残念」の二者択一の状態から転換してください。むしろ、真実には常に、より微妙な違いがあることをしましょう。アラート生成という小さな問題から、より全体的に何を許容できるかを考えるように切り替えます。これらの教に基づいて、SLO、アラートを採用することを積極的に検討し、アラート疲れを軽減して、注意を適切に絞り込むようにします。
 何よりも、本番環境に進む前には、わからないことがある、という事実を受け入れましょう。未知のことを、うまく扱えるようになりましょう。
 多くのことを取り上げてきましたが、さらに掘り下げるべきことがあります。可観測性の概念をさらに詳しく調べたければ、 Charity Majors、 Liz Fong-Jones, George Miranda による Observability Engineeringを勧めます*1。 また、SLO、SLIなどに関する幅広い考察 の優れた出発点として、 Site Reliability Engineering The Site Reliability Workbook #2 の両方を勧めます。 なお、この2冊は、 主にGoogleで行われている(あるいは、行われていた)方法という観点から書かれていることに注意が必要です。つまり、これらの概念は、必ずしも自分の環境に適用できるとは限りません。あなたはおそらくGoogleではないし、Google規模の問題を抱えているわけでもないでしょう。とはいえ、この書籍には、依然として推奨すべき点がたくさんあります。
 次の11章では、これまでと異なる全体的な視点からシステムを捉え、粒度の細かいアーキテクチャがセキュリティ領域で提供できるユニークな利点と課題について、検討します。


11章 セキュリティ
■セキュリティコントロールの種類
・予防的
 攻撃の発生を阻止する。これには、シークレットのセキュアな保存、保存時、転 送時のデータ暗号化、適切な認証認可メカニズムの実装が該当する。
・検知的
 攻撃が発生している、あるいは発生したという事実を警告する。アプリケーションファイアウォール、侵入検知サービス(IDS)などが、良い例。
・対応的
 攻撃中および攻撃後の対応を支援する。システムを再構築するための自動メカニズム、データを復元するバックアップ、インシデント発生時の適切なコミュニケーション計画が不可欠となる。

 システムを適切に保護するには、上記の3つすべてを組み合わせる必要があり、それぞれの種類が複数ある場合があります。城の例に戻ると、複数の壁は、複数の予防的コントロールを表します。監視塔とのろしを設けて、攻撃が発生しているかどうかを確認することもできます。最後に、攻撃の後に扉や壁を強化する場合に備え、大工や石工を待機させるかもしれません。もちろん、あなたが築城で生計を立てている可能性は低いので、本章の後半で、マイクロサービスアーキテクチャにおける、これらのコントロールの例を見ていきましょう。

■サイバーセキュリティの5つの機能
・特定
・保護
・検知
・対応
・復旧

■まとめ
 本章で明らかにしたように、セキュアなシステムを構築することは、1つのことを行うだけではありません。システムを全体的に眺め、ある種の脅威モデリングを行って、とのような種類のセキュリティコントロールを導入する必要があるかを理解しなければなりません。
 セキュリティコントロールを考えるとき、セキュアなシステムを構築するには、組み合わせが不可欠です。多層防御は、複数の保護を講じることだけではなく、よりセキュアなシステムを構築するための多面的なアプローチを意味します。
 再び本書の中心的なテーマに戻ります。システムをより粒度の細かいサービスに分解することで、問題解決のための選択肢が増えます。マイクロサービスは、あらゆる侵害の影響を軽減する可能性があります。加えて、データが機密の場合の、より複雑でセキュアなアプローチのオーバーヘッドと、危険性がより低い場合の、軽量なアプローチとの間のトレードオフの検討が可能になります。
 アプリケーションセキュリティ全般を広く知るには、Laura Bellらによる Agile Application Security を勧めます。
 次に、「レジリエンス」(回復性)に目を向けながら、システムの信頼性をより高める方法を見ていきます。


12章 レジリエンス
 単一プロセスモノリシックアプリケーションでは、あまり多くの判断を行いません。システムの正常性は、2つの場合で判断されます。プロセスが稼働しているか、停止しているかのどちらかです。しかし、マイクロサービスアーキテクチャでは、ずっと多い微妙な状況を考慮する必要があります。どのような状況でも、行うべき適切なことは、多くの場合、技術的な判断ではありません。ショッピングカートが停止した際、我々は、何が技術的に可能なのかを理解していますが、ビジネスの状況を理解していない限り、どのような対策を取るべきかを理解していません。例えば、サイト全体を閉じるが、商品カタログを閲覧できるようにする、または、カートコントロールを含むUI部分を、注文用の電話番号に置き換える、などの対応が考えられます。しかし、複数サービスを使う顧客向けインタフェースや、複数の下流コラボレータに依存するサービスでは、「これが停 止したらどうなるか」を考え、何をすべきかを把握する必要があります。
 機能横断要件の観点から各機能の重要度を考えることで、何ができるかをよりよく理解できるでしょう。障害が発生したときにグレースフルに対処できるように、技術的観点からできることを考えてみましょう。

■まとめ
 ソフトウェアがユーザの生活に不可欠なものになるほど、我々が作成するソフトウェアのレジリエンスを向上させる意欲がより高くなります。しかし、本章で説明したように、ソフトウェア、インフラについて考える「だけ」では、レジリエンスを実現できません。人プロセス、組織についても、考える必要があります。本章では、David Woodsが説明す レジリエンスの4つの中心的な概念について、 説明しました。
・堅牢性(ロバストネス、 robustness)
 想定される混乱を吸収する能力
・回復性 (rebound)
 衝撃的な出来事から復旧する能力
・グレースフルな拡張性 (graceful extensibility)
 想定外の状況に対処する能力
・持続的な適応性 (sustained adaptability)
 変化する環境、利害関係者、 要求に継続的に適応する能力

 マイクロサービスをより綿密に検討すると、システムの「堅牢性」を改善できる多くの方法があることがわかります。しかし、堅牢性の改善は、コストをかけずにできるわけではありません。どの選択肢を使うかを決める必要があります。サーキットブレーカー、タイムアウト、冗長性、分離、冪等性といった主な安定性パターンは、すべて自由に使うことができますが、いつどこで使うかを決めなければなりません。ただし、このような綿密な概念を超えて、我々が知らないことに常に目を向ける必要もあります。
 また、どの程度のレジリエンスが必要なのかも、考える必要があります。これは、ほとんどの場合、システムのユーザ、ビジネスオーナーが定義することです。あなたは技術者として、どのように行われるかを管理できます。しかし、どのようなレジリエンスが必要かを知るには、ユーザ、プロダクトオーナーとの良好で頻繁で密なコミュニケーションが必要でしょう。
 本章の前半で持続的な適応性について議論する際に使った、 David Woodsの引用に戻 りましょう。

 これまでどんなにうまくやっていても、どれほど成功していても、未来は異なる可能性があり、うまく適応できないかもしれない。その新しい未来に直面すると、我々は不安定で脆弱かもしれない。

 何度同じ質問をしても、不確かな未来に備えているかどうかを理解するのには、役立ちません。何がわかっていないかは、わかりません。絶えず学習し質問するという方法を採用するのが、レジリエンスを強化する上での鍵です。
 安定性パターンの1つである冗長性は、非常に効果的です。この考えは、次の13章にうまくつながります。13章では、マイクロサービスをスケールさせるさまざまな方法を検討します。これは、より多くの負荷を処理する上で役立つだけでなく、システムに冗長性を実装する上でも有効であり、結果的にシステムの堅牢性を向上させることができます。


13章 スケーリング
■まとめ
 このように、どのような種類のスケーリングを模索するにしても、マイクロサービスには、問題へのアプローチに関して異なる選択肢があります。
 スケーリングの軸は、どのような種類のスケーリングを利用できるかを検討する際に便利なモデルです。
・垂直スケーリング(vertical scaling)
 ひと言で言えば、より強力なマシンを導入すること。
・水平複製 (horizontal duplication)
 同じ処理を実行できるものを、 複数持つこと。
・データのパーティション分割 (data partitioning)
 データの何らかの属性に基づいて、 作業を分割すること。例えば、顧客グループ。
・機能分解 (functional decomposition)
 種類によって作業を分離すること。例えば、マイクロサービス分解。

 上記の多くでポイントとなるのは、自分が何を望んでいるかを理解することです。遅延を改善するためのスケーリングに効果的なテクニックであっても、ボリュームのためのスケーリングにはあまり効果的でないことがあります。
 しかし、ここまで説明したスケーリングの多くがシステムの複雑さを増やすことも、理解してもらえたと思います。したがって、変更をしたいものに的を絞り、時期尚早な最適化の危険を避けることが重要です。
 今まで、裏側で起こっていることを観察してきましたが、次の14章から、システムの最も目に見える部分、すなわちUIに移ります。


14章 UI
■まとめ
 これまで示してきたように、機能分解はサーバ側に留まる必要はなく、専任フロントエンドチームを持つことは、不可避ではありません。サポートするマイクロサービスを利用でき、集中的なエンドツーエンドデリバリを可能にするUIを構築する、さまざまな方法を紹介しました。


15章 組織構造
■まとめ
 コンウェイの法則は、組織に合わないシステム設計を強制することの危険を、改めて認識させてくれます。そして、少なくともマイクロサービスでは、強い所有権が標準であるモデルに向かうことを示しています。マイクロサービスを共有したり、大規模な共同所有権を持とうとしたりすると、マイクロサービスの利点が損なわれてしまうことが多いでしょう。
 組織、アーキテクチャが一致していないと、本章で説明したように、緊張関係が発生します。この2つの関係性を理解することで、これから構築するシステムが、組織にとって意味があるものかを確認できるのです。
 このテーマをさらに詳しく調べたい場合、以前に紹介したTeam Topologiesに加え、 James Lewisの講演 「Scale, Microservices and Flow」 *も絶対に勧めます。私は、この講演から、本章の構想に役立つ多くのヒントを得ました。本章で紹介した考え方をもっと深く探求したい場合、視聴する価値があります。
 次の16章では、すでに触れた「アーキテクトの役割」について、より深く掘り下げていきます。


16章 進化的アーキテクト
■まとめ
本章のまとめとして、 私が進化的アーキテクトの主な責務だと考えているものを、紹介します。
構想
 システムが顧客、組織の要件を満たすのを助けるシステムの技術的構想を明確に伝えるようにする。
共感
 顧客、 同僚に対する自分の判断の影響を理解する。
協調
 構想の定義、改良、 実行を支援するために、できるだけ多くの仲間、同僚と関わる。
適応性
 顧客、組織からの要求により、 技術的構想を変更するようにする。
自律性
 チームに対して、 標準化、 自律性の実現の間の適切なバランスを見出す。
ガバナンス
 実装しているシステムを技術的構想に合わせ、人々が正しいことするのを簡単にする。

 進化的アーキテクトは、このような中心的な責務を果たすことは、常にバランスを取る行為であることを理解している人です。我々は、常に何らかの力に押されています。どこで押し返すか、流れに乗ってどこに行くかを理解するには、多くの場合、経験が必要です。しかし、我々を変化に駆り立てるあらゆる力に対する最悪の対応は、考え方を硬直させ、固定化させてしまうことです。
 本章のアドバイスの多くは、あらゆるシステムアーキテクトに適用できますが、マイクロサービスでは、さらに多くの判断が求められます。したがって、これらすべてのトレードオフのバランスをうまく取れるようになることが不可欠です。進化的アーキテクトについて、さらに掘り下げて調べたい場合、すでに引用した Building Evolutionary Architectures だけでなく、 Gregor Hohpe による The Software Architect Elevator を勧めます。この書籍により、アーキテクトがハイレベルな戦略的思考、現場におけるデリバリの間の隙間を埋める方法を理解できるようになります。
 本書は、そろそろ終わりに近づいています。ここまで、多くの領域をカバーしました。「あとがき」では、ここまで学んできたことをまとめます。


あとがき
■マイクロサービスとは
 1章で紹介したように、「マイクロサービス」は、独立デプロイ可能性に焦点を当てたサービス指向アーキテクチャ(SOA)の一種です。「独立デプロイ可能性」とは、他のマイクロサービスを変更する必要なしに、マイクロサービスを変更し、そのマイクロサービスをデプロイし、その機能をエンドユーザにリリースできることを意味します。マイクロサービスアーキテクチャを最大限に活用することは、この概念を採用することです。通常、各マイクロサービスをプロセスとしてデプロイし、何らかの形式のネットワークプロトコルを介して、他のマイクロサービスとの通信を行います。マイクロサービスの複数インスタンスをデプロイすることは、一般的です。これにより、さらなるスケールを提供したり、冗長性を持たせることで、堅牢性を向上させたりすることができます。
 独立デプロイ可能性を実現するには、あるマイクロサービスを変更する際に、他のマイクロサービスとの対話を壊さないようにする必要があります。そのためには、他のマイクロサービスとのインタフェースを不変にし、後方互換性がある方法で変更を行う必要があります。2章で説明した「情報隠蔽」は、できるだけ多くの情報(コード、データ)をインタフェースの背後に隠蔽する、というアプローチでした。サービスインタフェースでは、コンシューマを満足させる必要最低限のことだけを、公開すべきです。公開する情報が少ないほど、行った変更が後方互換性を持つようにすることが、より簡単になります。また、情報隠蔽により、コンシューマに影響しないような方法で、マイクロサービス境界内で技術的な変更を加えることができます。
 独立デプロイ可能性を実現する主な方法として、「データベースの隠蔽」があります。マイクロサービスがデータベースに状態を保存する必要がある場合、データベースを外部から完全に隠蔽すべきです。内部データベースを、外部コンシューマに直接公開してはなりません。そうすることで、この2つの間の結合が強くなりすぎ、独立デプロイ可能性が損なわれてしまうからです。一般に、複数のマイクロサービスのすべてが、同じデータベースにアクセスしないようにしてください。
 マイクロサービスは、「ドメイン駆動設計」(DDD Domain-Driven Design) と非常にうまく連携します。ドメイン駆動設計は、マイクロサービス境界を見つけるのに役立つ概念であり、結果として得られるアーキテクチャは、ビジネスドメインに基づいたものになります。組織が、よりビジネス中心のITチームを作る場合、ドメイン駆動設計は極めて有益です。ビジネスドメインのある部分に焦点を当てたチームが、ビジネスのその部分に合致するマイクロサービスの所有権を取得できます。

■マイクロサービスへの移行
 マイクロサービスは、「多く」の複雑さをもたらします。マイクロサービスを使う理由を真剣に検討する必要があるほどの、複雑さです。新規システムでは、単純な単一プロセスモノリスから出発することが、完全に理にかなっていると、依然として確信しています。しかし、時間とともに、我々は多くを学び、現在のシステムアーキテクチャが、もはや目的にそぐわないことに気付きます。その時点で変更を検討するのが適切です。
 マイクロサービスアーキテクチャから「何」を得ようとしているかを理解することが、重要です。目標は何ですか。マイクロサービスへの移行がもたらすことを期待する良い結果は、何ですか。目指す結果は、モノリスを「どのように」分割するかに直接影響します。スケーリングにうまく対応できるようにするために、システムアーキテクチャを変更する場合には、組織の自律性を向上させることが主な目的である場合とは、異なる変更を行うことになるでしょう。詳しくは、3章で説明しています。また、私の書いた Monolith to Microservices でさらに詳細に説明しています。
 マイクロサービスの問題の多くは、本番環境で初めて明らかになるものです。したがって、「ビッグバン」書き換えではなく、既存のモノリスを漸進的、進化的に分解することを、強く勧めます。作成したいマイクロサービスを特定し、モノリスから適切な機能を切り出し、新しいマイクロサービスを本番環境にデプロイし、そのマイクロサービスを実際に使い始めるのです。そのようにすると、目的に向かって進んでいるかがわかります。また、次のマイクロサービスの切り出しをより簡単にする、多くのことも学ぶでしょう。あるいは、マイクロサービスは進むべき道ではない、ということがわかるかもしれません。

■通信スタイル
 4章では、マイクロサービス間の主な通信方法をまとめました。それを、図A-1に再び示します。これは普遍的なモデルではなく、最も一般的なさまざまな通信スタイルの概要を示すことだけを目的としています。
「リクエスト/レスポンス」通信では、マイクロサービスは、下流マイクロサービスにリクエストを送信し、レスポンスを期待します。同期リクエスト/レスポンスでは、リクエストを送信したマイクロサービスインスタンスに、レスポンスが戻ってくることを期待します。非同期リクエスト/レスポンスでは、上流マイクロサービスの別のインスタンスにレスポンスを戻すことができます。
「イベント駆動」通信では、マイクロサービスがイベントを発行し、(他のマイクロサービスが、そのイベントに関心がある場合)他のマイクロサービスがそのイベントに反応できます。イベントは、事実の表明にすぎません。起こったことに関して共有される情報です。イベント駆動通信では、マイクロサービスは、別のマイクロサービスに実行すべきことを指示しません。イベントを共有するだけです。その情報で何をするかの判断は、下流マイクロサービスに任されます。イベント駆動通信は、本質的に非同期になります。1つのマイクロサービスが、複数のプロトコルで通信することもあります。例えば図A-2では、Shippingサービスが、リクエスト/レスポンス通信用にRESTインタフェースを提供し、変更時にイベントを発行します。
 イベント駆動連携は、より疎結合のアーキテクチャ構築をより簡単にしますが、システムの振る舞いを理解するために、多くの労力が必要になることがあります。さらに、ここの種の通信では、メッセージブローカーなどの専門技術を必要とすることが多く、問題がさらに複雑になります。フルマネージドのメッセージブローカーを使用できる場合、ここの種のシステムのコストを下げることができるでしょう。
 リクエスト/レスポンス、イベント駆動の対話モデルは、どちらにもふさわしい場所があり、どちらを使うかは個人的な好みであることが多いものです。問題によっては、あるモデルが別のモデルよりも適している場合があり、マイクロサービスアーキテクチャでは、さまざまなスタイルの混在が一般的です。

■ワークフロー
 複数のマイクロサービスを連携させて、包括的な操作を実行する場合、6章で説明した「サーガ」を使ってプロセスを明示的にモデル化することを検討してください。
 一般に、サーガを使用できる状況では、分散トランザクションを避けるべきです。分散トランザクションでは、システムを著しく複雑にし、問題のある障害モードがあり、たとえ動作しても、期待する結果を提供できないことが多いのです。事実上すべてのケースにおいて、複数のマイクロサービスにわたるビジネスプロセスの実装には、サーガの方が適しています。
 サーガには、「オーケストレーション」ベースのサーガ、「コレオグラフィ」ベースのサーガという、2つのスタイルがあります。オーケストレーションベースのサーガは、中央オーケストレータを使って、他のマイクロサービスと連携し、処理が確実に行われるように調整します。一般に、これは単純でわかりやすいアプローチですが、注意しないと、中央オーケストレータはやりすぎてしまう可能性があり、複数チームが同じビジネスプロセスを扱う際、競合の原因になることがあります。コレオグラフィベースのサーガには、中央コーディネータがありません。代わりに、ビジネスプロセスの責務が、複数の連携マイクロサービスに分散されます。これは、実装がより複雑なアーキテクチャになり、適切に動作させるための作業が増える一方で、結合が発生しにくく、複数チームに対してうまく機能します。
 個人的には、コレオグラフィベースのサーガが好きですが、これを多く使って、実装で多くの間違いを繰り返してきました。私の一般的なアドバイスとしては、単一チームがプロセス全体に責任を持つ場合、オーケストレーションベースのサーガはうまくいきますが、複数チームでは問題が大きくなります。プロセスに複数チームの連携が求められる状況では、コレオグラフィベースのサーガで複雑さが増えるのは、当然と言えます。

■ビルド
 各マイクロサービスには、独自のビルド、独自のCIパイプラインが必要です。マイクロサービスを変更する際、私は、そのマイクロサービスを単独でビルドできることを期待します。すべてのマイクロサービスを一緒にビルドしなければいけない状況を避けてください。独立デプロイ可能性が、非常に難しくなるからです。
 7章で説明した理由から、私はモノリポを支持しません。本当にモノリボを使いたい場合、所有権の明確な境界線、ビルドの潜在的な複雑さに関して、それが引き起こす課題を理解してください。しかし、モノリポマルチリポのどちらを使うにしても、各マイクロサービスが独自のCIビルドプロセスを持ち、他のビルドから独立して、そのプロセスをトリガーできるようにしてください。

■デプロイ
 通常、マイクロサービスを、プロセスとしてデプロイします。このプロセスを、物理マシン、仮想マシン、コンテナ、FaaSプラットフォームにデプロイできます。理想的にデプロイした環境でマイクロサービスをできるだけ互いに分離したいでしょう。多くのコンピューティングリソースを使い尽くすあるマイクロサービスが、別のマイクロサービスに影響を及ぼすような状況を、望みません。つまり、一般に、各マイクロサービスが、区分されたOS、コンピューティングリソースを使うようにしたいのです。コンテナは、各マイクロサービスインスタンスに区分されたリソースを与えるのに、特に効果的です。これによって、コンテナが、マイクロサービスデプロイのための優れた選択肢になります。
 Kubernetes は、複数マシンにわたってコンテナワークロードを実行する場合に、とても便利です。しかし、Kubernetesは複雑さの原因となるので、マイクロサービスの数が少ない場合、Kubernetesを勧めません。可能であれば、マネージドKubernetesクラスタを使ってください。Kubernetesの複雑さを、ある程度回避できます。
 FaaSは、コードのデブロイに新たに出現した興味深いパターンです。コピーがいくつ必要かを指定するのではなく、FaaSプラットフォームにコードを提供し、「これが起こったら、このコードを実行してください」と言うだけです。これは、開発者の観点から見ると「本当に」素晴らしいことであり、多くのサーバ側開発の将来は、おそらくこのよう抽象化に向かうと思います。ただし、現在の実装に、問題がないわけではありません。マイクロサービスに関しては、まず、マイクロサービス全体を単一の「関数」としてFaaSプラットフォームにデプロイすると、 何の問題もなく始めることができます。
 最後に、1つ注意点があります。デプロイ、リリースの概念を、頭の中で区別してください。何か本番環境にデプロイしたからといって、ユーザにリリースしなければならないわけではありません。この2つの概念を区別すると、ソフトウェアをさまざまな方法でロールアウトする機会が広がります。例えば、カナリアリリース、並列実行を使う方法です。詳しくは、8章で説明しています。

■テスト
 ユーザに公開する前に、ソフトウェア品質に関するフィードバックを迅速に得られる。自動化された機能テストを用意することは、非常に理にかなっており、そうすべきです。章で調べたように、マイクロサービスでは、自分で書ける各種のテストに関して、多くの選択肢があります。
 しかし、他の種類のアーキテクチャと比べ、マイクロサービスアーキテクチャでは、エンドフーエンドテストが特に問題になることがあります。マイクロサービスアーキテクチャでは、より単純な非分散アーキテクチャよりも、エンドツーエンドテストの作成、メテナンスにコストがかかります。また、テスト自体が、必ずしもコードの問題を特定するとは限らない、多くの失敗を引き起こす可能性があります。複数チームにわたるエンドサーエンドテストは、特に困難です。
 エンドツーエンドテストへの依存を、徐々に減らすようにしてください。エンドツーエンドテストに対する労力を、コンシューマ駆動契約、スキーマ互換性確認、本番環境でのテストに置き換えることを検討してください。このような活動の方が、エンドツーエンドテストよりもずっと効率的に、分散システムにおける問題を迅速に把握することができます。

■監視と可観測性
 10章では、「監視」(モニタリング)は、システムに対して実行する活動ですが、結果で「はなく活動を重視することが問題であることを説明しました。このことは、本書で繰り返し述べています。代わりに、システムの「可観測性」(オブザーバビリティ)を重視すべきです。可観測性は、外部出力を調べることで、システムが何を行っているかをどの程度理解できるかを表します。優れた可観測性を持つシステムを作るには、この考え方をソフトウェアに組み込み、適切な種類の外部出力を利用できるようにする必要があります。
 分散システムは奇妙な方法で失敗することがあり、マイクロサービスも同様です。 システム障害のすべての原因を予測することはできないので、問題を診断、修正するために事前に必要な情報を知ることは難しいことがあります。想定外の方法で、このような外部出力を調べるためのツールを利用することが、ますます重要になります。この考え方を念頭に開発されたLightstep Honeycombのようなツールを検討することを、勧めます。
 最後に、システムの規模が大きくなるほど、常にどこかでエラーが発生する可能性がますます高くなります。しかし、大規模システムでは、1台のマシンに問題が発生したからといって、必ずしも全員が行動を起こす必要はなく、必ずしも午前3時にを起こす結果になるわけでもありません。並列実行、合成トランザクションのような「本番環境でのテスト」のテクニックを使えば、エンドユーザに実際に影響し得る問題を、 ずっと効率的に見つけることができます。

■セキュリティ
 マイクロサービスでは、アプリケーションを多層防御する機会が増え、その結果よりセキュアなシステムにつながります。一方、マイクロサービスでは、攻撃対象領域が広くなることが多いので、攻撃にさらされる危険が高くなります。このバランスを取るためには、セキュリティを総合的に理解することが非常に重要です。これは、11章で説明しました。
 ネットワーク上を流れる情報が増えると、データの保護を検討することが重要になります。また、品数が増えると、自動化が、マイクロサービスセキュリティの不可欠な要素になります。間違いが起こりやすい手動プロセスを使って、パッチ、証明書、シークレットを管理すると、攻撃に対して脆弱になります。そのため、簡単に自動化できるツールを使ってください。
 JWTを使って、ラウンドトリップを追加せずに、認可ロジックを分散できます。これは、混乱した代理問題などの問題から保護するのに役立ち、同時に、マイクロサービスがさらに独立して動作できるようにします。
 最後に、ますます多くの人々が、「ゼロトラスト」の考え方を採用するようになっています。ゼロトラストでは、システムがすでに侵害されているかのように運用し、それに応じてマイクロサービスを構築する必要があります。これは、被害妄想的な姿勢のように見えるかもしれませんが、この原則を採用することで、システムセキュリティに対する見方が実際に単純化されるという意見に、私は賛同するようになっています。

■レジリエンス
 12章では、レジリエンス (回復性)全般を調べ、レジリエンスについて考えるときに検 討すべき、4つの主な概念を紹介しました。

堅牢性(ロバストネス、 robustness)
 想定される混乱を吸収する能力
回復性 (rebound)
 衝撃的な出来事から復旧する能力
グレースフルな拡張性 (graceful extensibility)
 想定外の状況に対処する能力
持続的な適応性 (sustained adaptability)
 変化する環境、利害関係者、要求に継続的に適応する能力

全体として、マイクロサービスアーキテクチャは、上に挙げた一部(すなわち、堅牢性、回復性)に役立ちますが、これらの項目からわかるように、マイクロサービスアーキテクチャだけでレジリエンスが高まるわけではありません。レジリエンスを高めることの多くは、チーム、組織の振る舞い、文化に関するものです。
 基本的に、アプリケーションの堅牢性を向上させるためには、何か明示的に行う必要があります。堅牢性は無料ではありません。マイクロサービスは、システムのレジリエンスを改善する選択肢を与えてくれますが、我々がそこから選択しなければなりません。例えば別のマイクロサービスの呼び出しに失敗することがあり、マシンは停止することがあり、適切なネットワークバケットに問題が発生することがあることを、理解しなければなりません。バルクヘッド、サーキットブレーカー、適切に設定されたタイムアウトなどの安定性パターンが、非常に有効でしょう。

■スケーリング
 マイクロサービスには、アプリケーションをスケールさせるさまざまな方法があります。13章では、以下に示すスケーリングの4つの軸を調べました。
垂直スケーリング (vertical scaling)
 ひと言で言えば、より強力なマシンを導入すること。
水平複製 (horizontal duplication)
 同じ処理を実行できるものを、複数持つこと。
データのパーティション分割 (data partitioning)
 データの何らかの属性に基づいて、作業を分割すること。例えば、顧客グループ。
分解 (functional decomposition)
 種類によって作業を分離すること。例えば、マイクロサービス分解。

 スケーリングでは、まず、簡単なものから実施してください。垂直スケーリング、水平複製は、ここで紹介する他の2つの軸と比べ、迅速かつ簡単です。それでうまくいけば、素晴らしいことです。うまくいかなければ、他のメカニズムを検

読書状況:読み終わった 公開設定:公開
カテゴリ: 本・雑誌
感想投稿日 : 2023年9月9日
読了日 : 2023年9月9日
本棚登録日 : 2023年9月9日

みんなの感想をみる

コメント 0件

ツイートする