Envoy のアーキテクチャ:リスナー、クラスター、フィルターチェーン
リクエストが、到着したソケットから送信先のアップストリームまで、実際にどのように Envoy 内を流れるか。
Envoy の設計は、その創設の目標から直接導かれています。ネットワークをアプリケーションに対して透過的にし、ネットワークの問題とアプリケーションの問題を素早く区別できるようにすることです。この目標が、Envoy のすべての設定の元になっているリスナー、クラスター、フィルターという語彙を形作っています。このガイドでは、それぞれが何をするのか、リクエストがそれらをどう通過するのかを説明します。
ダウンストリームとアップストリーム
Envoy は、リクエストを送ってくるものをダウンストリーム、そのリクエストの転送先をアップストリームと呼びます。ダウンストリームは、エンドユーザーのブラウザ、メッシュ内の別のサービス、Envoy に接続を開く任意のものです。アップストリームは、Envoy がルーティングすると決めた先、つまりアプリケーションインスタンス、別のサービス、外部 API です。Envoy のすべての設定は、この線のどちら側かに位置します。
リスナー:接続の入口
リスナーはポートにバインドして接続を受け付けます。1 つの Envoy インスタンスが複数のリスナーを定義でき、それぞれが独自のポートと処理パイプラインを持ちます。たとえば 1 つのインスタンスが、443 で TLS を終端しつつ、8080 では暗号化されていないトラフィックを、まったく別のルールで処理できます。接続がルーティングされる前にリスナーが行う必要があること、つまり TLS の終端やプロトコルの検出などは、それにアタッチされたフィルターを通じて行われます。フィルターについては、このシリーズの次のガイドで詳しく説明します。
クラスター:接続の行き先
クラスターは、Envoy がトラフィックをルーティングできる、1 つ以上のアップストリームエンドポイントからなる、名前付きの論理グループです。Kubernetes の経験があれば、わかりやすい対比は次のとおりです。クラスターはおおよそ Service に相当し、その中の個々のエンドポイントは、その背後にある Pod におおよそ相当します。Envoy は各エンドポイントの状態を追跡し、クラスターに設定されたロードバランシングポリシーを適用して、リクエストごとに正常なものの中から宛先を選びます。
フィルターとフィルターチェーン
リスナーが接続を受け付けると、データはフィルターの列を流れます。フィルターは、それぞれが 1 つの仕事をする小さく焦点の絞られた単位で、連結されてフィルターチェーンになります。最も基本的なフィルターはネットワークレベル(TCP または UDP)で、上位のプロトコルとして何も解釈されていない生のバイトストリームに対して動作します。Envoy には、MongoDB、Redis、Kafka のプロトコル処理用のネットワークフィルターなどが最初から付属しています。
特に HTTP トラフィックでは、特定の 1 つのネットワークフィルターが重い処理の大半を担います。HTTP Connection Manager です。生のバイトを HTTP のリクエスト、ヘッダー、ボディにパースし、トラフィックが単なるバイトではなく HTTP になった後で動作する、独自の入れ子の HTTP レベルのフィルターのチェーン(アクセスログ、リトライ、ヘッダー操作など)を公開します。このシリーズの次のガイドは、それだけを扱っています。
ルート:クラスターの選択
トラフィックが HTTP 層に到達すると、ルートが、リクエスト自体の特性(ホスト、パス、ヘッダー)に照らして、どのクラスターに送るかを決定します。example.com/api へのリクエストは example-com クラスターに送るルートに一致し、別のホストやパスはまったく別のルートに一致する、といった具合です。ルートのマッチングが、「何らかの HTTP リクエストが到着した」を、「これが属する特定のクラスターはここだ」に変えます。
まとめ:リクエストの経路
ダウンストリームクライアント
│
▼
リスナー(ポートにバインド)
│
▼
フィルターチェーン(ネットワークフィルター、次に HTTP Connection Manager)
│
▼
ルートのマッチング(ホスト、パス、ヘッダー)
│
▼
クラスター(名前付きのエンドポイントのグループ)
│
▼
ロードバランシング + ヘルスチェック
│
▼
アップストリームエンドポイント
リクエストはリスナーに到着し、そのリスナーのフィルターチェーンを流れ、ルーティングルールによってクラスターに対応付けられ、Envoy のクラスターマネージャーが、そのクラスター内の正常なエンドポイントを、実際に送る先として選びます。Envoy が行うすべてのこと、つまり TLS、レート制限、リトライ、可観測性は、独立した関心事として存在するのではなく、これらの段階のどれかに結びついています。これはまさに、プロジェクトが実現しようとした「ネットワークは透過的で、問題は特定しやすい」という設計です。すべての段階が明示的で検査可能なため、応答の遅延やリクエストの失敗は、推測を必要とせず、通常は特定のリスナー、フィルター、クラスターにたどることができます。
各段階で何が起きるのかについて、このガイドが意図的に単純化している部分(ワーカースレッド、コネクションプーリング)を含め、はるかに詳細な説明が必要な場合は、Envoy 自身の「life of a request」のドキュメントが、内部のフロー全体を順を追って説明しています。