The Service Mesh: What every software engineer needs to know about the world’s most over-hyped technology
What is a service mesh?
誇大広告のわりに、サービスメッシュはアーキテクチャ的に非常に単純です。 これは、サービスの「隣」に固定された一連のユーザースペースプロキシ(「隣」の意味については後で説明します)と、一連の管理プロセスにすぎません。 プロキシはサービスメッシュのデータプレーンと呼ばれ、管理プロセスはそのコントロールプレーンと呼ばれます。 データプレーンは、サービス間の呼び出しをインターセプトし、これらの呼び出しで「処理を実行」します。 コントロールプレーンはプロキシの動作を調整し、オペレーターであるユーザーがメッシュ全体を操作および測定するためのAPIを提供します。
https://uploads-ssl.webflow.com/625ee9b2f6a4ec3997f9c11b/62a0d2912bd35a4d27f84ccf_diag1.png
Why does the service mesh make sense?
サービスメッシュのアイデアに初めて遭遇した場合、最初の反応が軽度の恐怖であったとしても許されます。サービスメッシュの設計は、アプリケーションにレイテンシを追加するだけでなく、リソースを消費し、大量のからくりを導入することを意味します。サービスメッシュをインストールして1分後、突然、数百または数千のプロキシを操作するために窮地に陥ります。なぜ誰かがこれをしたいのですか?
答えには2つの部分があります。 1つ目は、エコシステムで発生している他の変更のおかげで、これらのプロキシを展開するための運用コストを大幅に削減できることです。これについては後で詳しく説明します。
より重要な答えは、この設計が実際にはシステムに追加のロジックを導入するための優れた方法であるためです。これは、そこに追加できる機能がたくさんあるだけでなく、エコシステムを変更せずに追加できるためです。実際、サービスメッシュモデル全体は、まさにこの洞察に基づいています。マルチサービスシステムでは、個々のサービスが実際に何をするかに関係なく、サービス間のトラフィックは機能の理想的な挿入ポイントです。
たとえば、Linkerdには、ほとんどのメッシュと同様に、HTTP / 2やgRPCなどのHTTP呼び出しに主に焦点を当てたレイヤー7機能セットがあります。機能セットは幅広いですが、次の3つのクラスに分類できます。
信頼性機能。再試行、タイムアウト、カナリア(トラフィックの分割/シフト)などを要求します。
可観測性機能。各サービスまたは個々のルートの成功率、待機時間、およびリクエスト量の集計。サービストポロジマップの描画。等
セキュリティ機能。相互TLS、アクセス制御など。
これらの機能の多くは、リクエストレベルで動作します(ゆえに「L7プロキシ」)。たとえば、サービスFooがサービスBarにHTTP呼び出しを行う場合、Foo側のlinkerd-proxyは、それぞれの観測されたレイテンシに基づいて、Barのすべてのインスタンス間でインテリジェントに呼び出す負荷分散を行うことができます。失敗した場合、およびべき等である場合は、要求を再試行できます。応答コードとレイテンシーを記録できます。同様に、Bar側のlinkerd-proxyは、許可されていない場合、またはレート制限を超えている場合、呼び出しを拒否できます。レイテンシーをその観点から記録できます。
プロキシは、コネクションレベルでも「何かを行う」ことができます。たとえば、Fooのlinkerd-proxyはTLS接続を開始し、Barのlinkerd-proxyはそれを終了でき、互いに相手のTLS証明書を検証できます。これにより、サービス間の暗号化だけでなく、暗号化された安全な形式のサービスIDが提供されます。 FooとBarは、彼らが本人であると「証明」することができます。
リクエストレベルであろうとコネクションレベルであろうと、注意すべき重要な点の1つは、サービスメッシュの機能はすべて本質的に運用上のものということです。 Linkerdには、リクエストペイロードのセマンティクスの変換、たとえばJSON blobにフィールドを追加したりprotobufを変換したり、については何もありません。 これは、ESBとミドルウェアについて話すときに再び触れる重要な違いです。
これが、サービスメッシュが提供できる一連の機能です。しかし、なぜそれらをアプリケーションに直接実装しないのでしょうか。なぜプロキシを気にするのですか?
Why is the service mesh a good idea?
機能セットは興味深いものですが、サービスメッシュのコアバリューは実際には機能にありません。 結局のところ、これらの機能をアプリケーション自体に直接実装することができます(実際、これがサービスメッシュの起源であることが後でわかります。)。1つの文にまとめる必要がある場合、サービスメッシュの価値は次のようになります。サービスメッシュは、モダンなサーバーサイドアプリケーションを実行するために重要な機能を提供します。その方法はスタック全体で均一で、アプリケーションコードから切り離されています。
一度にひとつずつ取り上げましょう。
最新のサーバーサイドソフトウェアを実行するために重要な機能。
もしあなたがパブリックインターネットに接続され、外部からの要求を受け取り、短い時間枠内でそれらに応答するトランザクション型のサーバー側アプリケーション(Webアプリ、APIサーバー、および最新のサーバー側ソフトウェアの大部分を考えてみてください)を構築しているとしたらー
また、このシステムを、同期的に相互に通信するサービスのコレクションとして構築しているとしたら、
また、このソフトウェアを継続的に変更して機能を追加するとしたら、
また、システムを変更している間もこのシステムを実行し続ける必要があるとしたら、
おめでとうございます。あなたはモダンなサーバーサイドソフトウェアを構築しています。
スタック全体で均一であること。 サービスメッシュによって提供される機能は重要であるだけでなく、サービスが記述されている言語、使用されているフレームワーク、記述者、展開方法、その他の開発または展開の詳細に関係なく、アプリケーション内のすべてのサービスに適用されます。
アプリケーションコードから切り離されていること。 最後に、サービスメッシュは、スタック全体で機能を均一に提供するだけでなく、アプリケーションの変更を必要としない方法で提供します。構成、更新、操作、保守などの運用上の所有権を含む、サービスメッシュ機能の基本的な所有権は、アプリケーションに関係なく、純粋にプラットフォームレベルにあります。アプリケーションはサービスメッシュを使用せずに変更でき、サービスメッシュはアプリケーションを使用せずに変更できます。
つまり、サービスメッシュは重要な機能を提供するだけでなく、グローバルで統一された、アプリケーションから独立した方法で提供します。 そのため、サービスメッシュの機能をサービスコードに実装することはできますが(すべてのサービスにリンクされたライブラリとしても)、このアプローチでは、サービスメッシュが提供する価値の中心にある分離と均一性は提供されません。
Who does the service mesh help?
都合の悪いことに、技術が実際に影響を与えるためには、人間がそれを採用しなければならないことがわかりました。 では、誰がサービスメッシュを採用するのでしょうか。 誰がそれから恩恵を受けますか?
上記の最新のサーバーソフトウェアとして上記で説明したものを構築している場合、チームは、ビジネスロジックを構築する仕事を行うサービス所有者と、これらのサービスが実行される内部プラットフォームを構築するプラットフォーム所有者に分けられると大まかに考えることができます。小規模な組織では、これらは同じ人である可能性がありますが、組織が大きくなるにつれて、これらの役割は通常、より明確になり、さらに細分化されます(ここでは、DevOpsの性質の変化、マイクロサービスの組織への影響などについて、さらに多くのことが言われています。ただし、とりあえず、これらの説明を与えられたものとして取り上げましょう。) 。
このレンズを通して見ると、サービスメッシュの直接の受益者はプラットフォームの所有者です。結局のところ、プラットフォームチームの目標は、サービス所有者がビジネスロジックを実行できる内部プラットフォームを構築し、サービス所有者が運用の厄介な詳細から可能な限り独立した状態に保つことです。サービスメッシュは、これを実現するために重要な機能を提供するだけでなく、サービス所有者に依存しない方法で提供します。
より間接的な方法ではありますが、サービスの所有者にもメリットがあります。サービス所有者の目標は、ビジネスロジックを構築する際に可能な限り生産的になることであり、心配する必要のある運用メカニズムが少ないほど、それは簡単です。例えば再試行ポリシーまたはTLSを実装するために追い詰められるのではなく、ビジネスロジックの関心に純粋に焦点を合わせ、プラットフォームが残りを処理することを信頼できます。それは彼らにとっても大きなプラスです。
プラットフォームとサービスの所有者間の分離の組織的価値はどれだけ誇張してもし過ぎることはありません。 実際、それがサービスメッシュが価値のある主な理由かもしれないと思います。
この教訓は、Linkerdの初期の採用者の1人が、サービスメッシュを採用した理由を教えてくれたときに学びました。その理由は、「人と話す必要がない」ためです。 これは、Kubernetesに移行していた大企業のプラットフォームチームでした。 彼らのアプリは機密情報を取り扱っていたため、クラスター上のすべての通信を暗号化したいと考えていました。 何百ものサービスと何百もの開発者チームがあり、彼らは各開発チームにTLSをロードマップに追加するよう説得することを楽しみにしてはいませんでした。 Linkerdをインストールすることで、機能の所有権を、それが重荷となる開発者の手から、最優先事項であったプラットフォームチームの手に移しました。 Linkerdは、技術的な問題を解決するというよりむしろ、組織的な問題を解決しました。
つまり、サービスメッシュは、技術的な問題の解決策というより、社会技術的な問題の解決策です。
Does the service mesh solve all my problems?
上記で概説した3つのクラスの機能(信頼性、セキュリティ、および可観測性)を見ると、サービスメッシュがこれらのドメインのいずれに対しても完全なソリューションではないことは明らかです。 Linkerdは、べき等であることがわかっている場合はリクエストを再試行できますが、サービスが完全にダウンした場合にユーザーに何を返すかを決定することはできません。アプリケーションはこれらの決定を行う必要があります。 Linkerdは成功率などを報告できますが、サービスの内部を調べて内部メトリックを報告することはできません。アプリケーションにインストルメンテーションが必要です。 Linkerdは相互TLSのようなことを「無料で」行うことができますが、セキュリティソリューションはそれだけではありません。
サービスメッシュが提供するこれらのドメインの機能のサブセットは、プラットフォーム機能であるものです。これは、次のような機能を意味します。
ビジネスロジックに依存しない機能。 FooとBarの間の呼び出しについてトラフィック遅延ヒストグラムが計算される方法は、Fooが最初にBarを呼び出している理由とはまったく関係ありません。
正しく実装するのが難しい機能。 Linkerdの再試行は、再試行の単純なアプローチが「再試行ストーム」やその他の分散システム障害モードへの確実なパスであるため、再試行バジェットなどの高度なものでパラメーター化されます。
均一に実装すると最も効果的な機能。相互TLSの仕組みは、誰もがそれらを実行している場合にのみ実際に意味があります。
これらの機能はアプリケーション層ではなくプロキシ層で実装されるため、サービスメッシュはアプリケーションレベルではなくプラットフォームレベルで機能を提供します。サービスがどの言語で書かれているか、どのフレームワークを使用しているか、誰が書いたか、どのようにしてそこにたどり着いたかは関係ありません。プロキシはそれらすべてから独立して機能し、この機能の所有権(構成、更新、運用、保守などの運用上の所有権を含む)は、純粋にプラットフォームレベルにあります。
Why does the service mesh make sense now?
この時点で、あなたは自分自身にこう言っているかもしれません。わかりました。このサービスメッシュが非常に優れているのなら、10年前に何百万ものプロキシをスタックに入れなかったのはなぜですか。
これには浅い答えがあります。それは、10年前は誰もがモノリスを構築していたため、サービスメッシュは必要なかったということです。それは本当ですが、私はポイントを逃していると思います。 10年前でも、大規模システムを構築するための実現可能な方法としての「マイクロサービス」の概念は広く議論され、Twitter、Facebook、Google、Netflixなどの企業で公に実践されていました。少なくとも私がさらされた業界の一部では、一般的な感情は、マイクロサービスは、たとえ本当に苦痛だったとしても、大規模システムを構築するための「正しい方法」であるというものでした。
もちろん、10年前にマイクロサービスを運用している企業がありましたが、それらは概して、サービスメッシュを形成するためにどこにでもプロキシをインストールしていませんでした。ただし、よく見ると、彼らは関連することを行っていました。これらの組織の多くは、ネットワーク通信用の特定の内部ライブラリ(「ファットクライアント」ライブラリと呼ばれることもあります)の使用を義務付けていました。 NetflixにはHysterixがあり、GoogleにはStubbyライブラリがあり、TwitterにはFinagleがありました。たとえば、Finagleは、Twitterのすべての新しいサービスに必須であり、接続のクライアント側とサーバー側の両方を処理し、再試行、要求ルーティング、負荷分散、およびインストルメンテーションを実装しました。これにより、サービス自体が実際に行ったこととは関係なく、Twitterスタック全体で一貫した信頼性と可観測性のレイヤーが提供されました。確かに、これはJVM言語でのみ機能し、アプリ全体を構築する必要のあるプログラミングモデルがありましたが、提供される操作機能はサービスメッシュの機能とほぼ同じでした。
そのため、10年前には、マイクロサービスだけでなく、サービスメッシュが現在解決しているのと同じ問題の多くを解決するproto-service-meshライブラリがありました。しかし、サービスメッシュはありませんでした。最初に何か他のものを変更する必要がありました。
そして、そこに深い答えがあり、過去10年間に起こった別の違いに埋もれています。それは、マイクロサービスの導入コストが劇的に削減されたことです。 10年前にマイクロサービスを公に使用していた上記の企業(Twitter、Netflix、Facebook、Google)は、膨大な規模と膨大なリソースを備えた企業でした。彼らには、重要なマイクロサービスアプリケーションを構築、展開、運用する必要性だけでなく、能力もありました。 Twitterのモノリスからマイクロサービスへの移行に費やされた膨大なエンジニアリング時間とエネルギーは想像力をかき乱します。この種のインフラストラクチャの操作は、中小企業にとって本質的に不可能でした。
これとは対照的に、マイクロサービスと開発者の比率が5:1または10:1のスタートアップに遭遇する可能性があり、さらに、それらはそれを処理するための設備が整っています。 50個のマイクロサービスを実行することが5人のスタートアップにとってもっともらしいアプローチである場合、明らかに何かがマイクロサービスを採用するコストを削減しました。
マイクロサービスの運用コストが劇的に削減されたのは、コンテナとコンテナオーケストレーターの採用が増えたことによるものです。そして、これは、どのような変更がサービスメッシュを可能にしたかという質問に対するより深い答えが存在するところです。サービスメッシュを運用可能にするのは、マイクロサービスを運用可能にするのと同じことです。KubernetesとDockerです。
なんで? Dockerは、パッケージングの問題という1つの大きな問題を解決します。アプリとその(ネットワーク以外の)実行時の依存関係をコンテナにパッケージ化できるようにすることで、アプリはどこにでも投げて実行できる代替可能なユニットになりました。同様に、Dockerを使用すると、ポリグロットスタックの実行が飛躍的に容易になります。コンテナーは実行のアトミックユニットであるため、デプロイと運用の目的では、コンテナー内に何が含まれているか、JVMアプリであるかJVMアプリであるかは重要ではありません。ノードアプリまたはGoまたはPythonまたはRuby。あなたはそれを実行するだけです。
Kubernetesは次のステップを解決します。「実行可能物」がたくさんあり、「これらの実行可能物を実行できるもの」(別名マシン)もたくさんあるので、それらの間のマッピングが必要です。広い意味で、Kubernetesに一連のコンテナと一連のマシンを与えると、このマッピングがわかります。 (もちろん、これは動的で常に変化するものです。新しいコンテナーがシステム内を移動したり、マシンが稼働したり停止したりします。しかし、Kubernetesはそれを理解しています。)
Kubernetesを使用すると、1つのサービスを実行するためのデプロイ時間のコストは、10のサービスを実行する場合とそれほど変わりません。実際、100のサービスを実行する場合とそれほど変わりません。これを、ポリグロットの実装を促進するパッケージングメカニズムとしてのコンテナと組み合わせると、さまざまな言語で記述されたマイクロサービスとして実装される大量の新しいアプリケーションが得られます。まさに、サービスメッシュが最も適した環境です。
そして最後に、サービスメッシュが現在実現可能である理由に到達します。Kubernetesがサービスに提供するのとまったく同じ均一性が、サービスメッシュの運用上の課題に直接適用できます。プロキシをコンテナにパッケージ化し、Kubernetesにどこにでも貼り付けるように指示します。デプロイ時のメカニズムがすべてKubernetesによって処理されるサービスメッシュを取得しました。
要約すると、サービスメッシュが10年前とは対照的に今では理にかなっている理由は、KubernetesとDockerの台頭により、アプリケーションをポリグロットマイクロサービスアーキテクチャとして簡単に構築できるようになり、サービスメッシュを実行する必要性が劇的に高まっただけではなく、サイドカープロキシのフリートを展開および維持するためのメカニズムを提供することにより、サービスメッシュの実行コストが劇的に削減されたためです。