Envoy: HTTP コネクション管理

# tldr
勉強がてらにEnvoyのドキュメントを邦訳してみました。ベースはGoogle Translateで、ところどころ不自然な箇所を直しています。

原文としたのEnvoyのドキュメントは[こちらのディレクトリ以下](https://github.com/envoyproxy/envoy/tree/master/docs)にあります（ライセンス：[Apache License 2.0](https://github.com/envoyproxy/envoy/blob/master/LICENSE), [NOTICE](https://github.com/envoyproxy/envoy/blob/master/NOTICE)）。


## HTTP コネクション管理

HTTPは現代のサービス指向アーキテクチャーの非常に重要なコンポーネントであり、Envoyは大量のHTTP固有の機能を実装しています。 EnvoyにはHTTP接続マネージャと呼ばれるネットワークレベルのフィルタが組み込まれています。このフィルタは、生のバイトを HTTP レベルのメッセージおよびイベント（例えば、受信したヘッダ、受信した Body データ、受信したトレーラなど）に変換する。また、アクセスロギング、リクエストIDの生成とトレース、リクエスト/レスポンスヘッダの操作、ルートテーブル管理、統計など、すべての HTTP 接続とリクエストに共通の機能も処理します。

HTTP 接続マネージャの設定

### HTTPプロトコル

Envoyの HTTP 接続マネージャは、HTTP/1.1、WebSockets、および HTTP/2をネイティブでサポートしています。 SPDY はサポートされていません。 Envoy の HTTP サポートは、まず第一に HTTP/2 多重化プロキシになるように設計されています。内部的には、 HTTP/2 の用語がシステムコンポーネントの説明に使われています。たとえば、HTTP 要求と応答はストリーム上で行われます。コーデック API は、さまざまな有線プロトコルから、ストリーム、要求、応答などのプロトコルに依存しない形式に変換するために使用されます。HTTP/1.1 の場合、コーデックはプロトコルのシリアル/パイプライン機能を HTTP のように見せます。より高い層への/2。つまり、大部分のコードでは、ストリームが HTTP /1.1 または HTTP/2 のどちらの接続で発生したのかを理解する必要はありません。

### HTTPヘッダーのサニタイズ

HTTP 接続マネージャは、セキュリティ上の理由からさまざまなヘッダサニタイズアクションを実行します。

### ルートテーブル設定

各 HTTP 接続マネージャフィルタには、関連付けられたルートテーブルがあります。ルートテーブルは、次の2つの方法のいずれかで指定できます。

- 静的に
- RDS API を介して動的に。

### 再試行プラグインの設定

通常、再試行中は、ホストの選択は元の要求と同じプロセスに従います。再試行プラグインを使用してこの動作を変更できます。これらは2つのカテゴリに分類されます。

- ホスト述語
  これらの述語は、ホストを「拒否」するために使用できます。これにより、ホストの選択が再試行されます。これらの述部はいくつでも指定でき、いずれかの述部がホストを拒否すると、ホストは拒否されます。

  Envoyは以下の組み込みホスト述語をサポートします
  - envoy.retry_host_predicates.previous_hosts：これは以前に試行されたホストを追跡し、既に試行されたホストを拒否します。

- 優先順位述部
  これらの述部は、再試行の優先順位を選択するときに使用される優先順位の負荷を調整するために使用できます。指定できる述語は1つだけです。

  Envoyは以下の組み込み優先順位述語をサポートします
  - envoy.retry_priority.previous_priorities：これは以前に試行された優先順位を追跡し、他の優先順位がその後の再試行でターゲットになるように優先順位の負荷を調整します。

構成された述語がホストを受け入れるか、または構成可能な最大試行数に達するまで、ホストの選択は続きます。

これらのプラグインを組み合わせて、ホストの選択と優先順位の負荷の両方に影響を与えることができます。カスタムフィルタを追加する方法と同じように、Envoyをカスタム再試行プラグインで拡張することもできます。

#### 設定例

たとえば、まだ試行されていないホストを優先するように再試行を設定するには、組み込みのenvoy.retry_host_predicates.previous_hosts述語を使用できます。

```
retry_policy：
  retry_host_predicate：
   - name：envoy.retry_host_predicates.previous_hosts
  host_selection_retry_max_attempts：3
```

これは以前に試みられたホストを拒否し、最大3回ホスト選択を再試行します。許容できるホストを見つけることが不可能である（述語を満たすホストがいない）か、または非常にありそうにない（唯一の適切なホストが非常に低い相対的な重みを持つ）シナリオに対処するために試行の限界が必要です。

再試行中に他の優先順位を試すように再試行を設定するには、組み込みのenvoy.retry_priority.previous_prioritiesを使用できます。


```
retry_policy：
  retry_priority：
    name：envoy.retry_priorities.previous_priorities
    config：
      update_frequency：2
```

これは、まだ使用されていない後続の再試行の優先順位をターゲットにします。 update_frequencyパラメーターは、優先順位の負荷を再計算する頻度を決定します。

これらのプラグインを組み合わせることができます。これにより、以前に試行されたホストと以前に試行された優先順位の両方が除外されます。

```
retry_policy：
  retry_host_predicate：
   - name：envoy.retry_host_predicates.previous_hosts
  host_selection_retry_max_attempts：3
  retry_priority：
    name：envoy.retry_priorities.previous_priorities
    host：
      update_frequency：2
```

### 内部リダイレクト

Envoyは内部的に302リダイレクトの処理、つまり302リダイレクトレスポンスの取得、新しいリクエストの合成、新しいルートマッチで指定されたアップストリームへの送信、そしてリダイレクトされたレスポンスを元のリクエストに対するレスポンスとして処理することをサポートします。

内部リダイレクトは、ルート設定のref：redirect action <envoy_api_field_route.RouteAction.redirect_action>フィールドで設定します。リダイレクト処理がオンの場合、アップストリームからの302応答はすべて、Envoyによって処理されているリダイレクトの影響を受けます。

リダイレクトが正常に処理されるためには、次のチェックに合格する必要があります。

1. 302応答してください。
1. 元のリクエストのスキームと一致する、有効な完全修飾URLを含むロケーションヘッダーを用意してください。
1. 依頼はEnvoyによって完全に処理されていなければなりません。
1. リクエストはボディを持ってはいけません。
1. x-envoy-original-urlヘッダーの存在によって決定されるように、要求は以前にリダイレクトされていてはなりません。

失敗すると、代わりにリダイレクトがダウンストリームに渡されます。

リダイレクトがこれらのチェックに合格すると、元のアップストリームに出荷されたリクエストヘッダーは次のように変更されます。

1. x-envoy-original-urlヘッダーに完全修飾の元の要求URLを入れます。
1. Authority / Host、Scheme、Pathの各ヘッダーをLocationヘッダーの値に置き換えます。

変更されたリクエストヘッダは、新しいルートが選択され、新しいフィルタチェーンを介して送信され、その後通常のEnvoyリクエストサニタイズがすべて行われた状態で上流に出荷されます。


#### 警告

信頼できないヘッダーを消去するなどのHTTP接続マネージャのサニタイズは一度だけ適用されることに注意してください。ルートごとのヘッダー変更は、元のルートと2番目のルートの両方が同じであっても適用されるため、不要なヘッダー値が重複しないように、ヘッダー変更ルールを慎重に設定してください。

サンプルリダイレクトフローは次のようになります。

1. クライアントがhttp://foo.com/barのGETリクエストを送信します
1. アップストリーム1は302と「location：http://baz.com/eep」を送信します。
1. Envoyは元の経路でのリダイレクトを許可するように設定されていて、新しいGETリクエストをUpstream 2に送信し、http://baz.com/eepに追加のリクエストヘッダー「x-envoy-original-url：http：//」を取得します。 foo.com/bar”
1. Envoyはhttp://baz.com/eepの応答データを元の要求に対する応答としてクライアントにプロキシします。

### タイムアウト

HTTP接続とその構成要素のストリームには、さまざまな設定可能なタイムアウトが適用されます。

- 接続レベルのアイドルタイムアウト
  これは、ストリームがアクティブでないアイドル期間に適用されます。

- 接続レベルのドレインタイムアウト
  これは、Envoyが開発したGOAWAYと接続終了の間のものです。

- ストリームレベルのアイドルタイムアウト
  これは個々のストリームに適用されます。それは接続マネージャとルートごとの粒度の両方で設定されるかもしれません。ストリーム上のヘッダー/データ/トレーラーイベントがアイドルタイムアウトをリセットしました。

- ストリームレベルの経路ごとのアップストリームタイムアウト
  これはアップストリーム応答、すなわちダウンストリーム要求の終わりからアップストリーム応答の終わりまでの時間の最大限界に適用される。これは、再試行ごとの単位で指定することもできます。

- ストリームレベルのルートごとのgRPC最大タイムアウト
  これはアップストリームのタイムアウトを制限し、タイムアウトをgrpc-timeoutリクエストヘッダーで上書きすることを可能にします。