HTTP 連線管理
HTTP 是現代面向服務架構的關鍵組件,Envoy 實作了大量的 HTTP 特定功能。Envoy 具有一個內建的網路層級過濾器,稱為 HTTP 連線管理器。
此過濾器將原始位元組轉換為 HTTP 層級的訊息和事件(例如,接收到標頭、接收到主體資料、接收到尾部等等)。
它還處理所有 HTTP 連線和請求通用的功能,例如 存取記錄、請求 ID 生成和追蹤、請求/回應標頭操作、路由表管理和 統計。
HTTP 協定
Envoy 的 HTTP 連線管理器原生支援 HTTP/1.1、HTTP/2 和 HTTP/3,包括 WebSockets。
Envoy 的 HTTP 支援的設計首先是作為 HTTP/2 多工代理。在內部,使用 HTTP/2 術語來描述系統元件。例如,HTTP 請求和回應發生在「串流」上。
編碼器 API 用於將不同的有線協定轉換為與協定無關的串流、請求、回應等形式。
在 HTTP/1.1 的情況下,編碼器將協定的序列/管線功能轉換為對更高層級看起來像 HTTP/2 的東西。這表示大多數程式碼不需要了解串流是源自 HTTP/1.1、HTTP/2 還是 HTTP/3 連線。
HTTP 生命週期
當下游 HTTP 編碼器成功解碼請求標頭對應時,即開始代理請求。
代理完成和串流被銷毀的時間點取決於上游協定以及是否啟用獨立半關閉。
如果啟用獨立半關閉,且上游協定是 HTTP/2 或 HTTP/3 協定,則在請求和回應都完成後(即透過接收尾部或標頭/主體並在兩個方向都設定 end-stream,且回應具有成功 (2xx) 狀態碼),串流就會被銷毀。
對於 HTTP/1 上游協定,或者如果禁用獨立半關閉,則當回應完成並到達其 end-of-stream 時(即當接收到尾部或設定了 end-stream 的回應標頭/主體時),即使請求尚未完成,串流也會被銷毀。如果請求在回應完成時不完整,則串流會被重設。
請注意,當發生錯誤或逾時,或對等端重設 HTTP/2 或 HTTP/3 串流時,代理可能會提前停止。
HTTP 標頭清理
HTTP 連線管理器會執行各種標頭清理動作,以確保安全性。
路由表配置
每個HTTP 連線管理器過濾器都有一個相關聯的路由表,可以透過以下兩種方式之一指定
靜態地。
透過RDS API動態地。
重試外掛程式配置
通常,在重試期間,主機選擇會遵循與原始請求相同的流程。重試外掛程式可用於修改此行為,它們分為兩類
- 主機謂詞
這些謂詞可用於「拒絕」主機,這將導致重新嘗試主機選擇。可以指定任意數量的這些謂詞,如果任何謂詞拒絕主機,則該主機將被拒絕。
Envoy 支援以下內建主機謂詞
- PreviousHostsPredicate
這將追蹤先前嘗試過的主機,並拒絕已嘗試過的主機。
- OmitCanaryHostsPredicate
這將拒絕任何標記為金絲雀主機的主機。主機透過在端點的過濾器中繼資料中為
envoy.lb
過濾器設定canary: true
來標記。請參閱 LbEndpoint 以取得更多詳細資訊。- OmitHostMetadataConfig
這將根據預定義的中繼資料比對條件拒絕任何主機。請參閱下方的配置範例以取得更多詳細資訊。
- 優先順序謂詞
這些謂詞可用於調整在選擇重試嘗試的優先順序時使用的優先順序負載。只能指定一個優先順序謂詞。
Envoy 支援以下內建優先順序謂詞
- PreviousPrioritiesConfig
這將追蹤先前嘗試過的優先順序,並調整優先順序負載,以便在後續的重試嘗試中以其他優先順序為目標。
主機選擇將會繼續,直到配置的謂詞接受主機或達到可配置的最大嘗試次數。
這些外掛程式可以組合使用,以影響主機選擇和優先順序負載。Envoy 也可以使用自訂重試外掛程式來擴展,類似於新增自訂過濾器的方式。
重試配置範例
PreviousHostsPredicate
例如,若要配置重試以優先選擇尚未嘗試過的主機,可以使用內建的PreviousHostsPredicate
24 routes:
25 - match:
26 prefix: "/"
27 route:
28 cluster: cluster_0
29 retry_policy:
30 retry_host_predicate:
31 - name: envoy.retry_host_predicates.previous_hosts
32 typed_config:
33 "@type": type.googleapis.com/envoy.extensions.retry.host.previous_hosts.v3.PreviousHostsPredicate
34 host_selection_retry_max_attempts: 3
35
36 clusters:
這將拒絕先前嘗試過的主機,並重試主機選擇最多 3 次。嘗試次數的限制對於處理以下情況是必要的:尋找可接受的主機是不可能的(沒有主機滿足謂詞)或非常不可能(唯一適合的主機的相對權重非常低)。
OmitHostMetadataConfig
若要根據主機的中繼資料拒絕主機,可以使用 OmitHostMetadataConfig
24 routes:
25 - match:
26 prefix: "/"
27 route:
28 cluster: cluster_0
29 retry_policy:
30 retry_host_predicate:
31 - name: envoy.retry_host_predicates.omit_host_metadata
32 typed_config:
33 "@type": type.googleapis.com/envoy.extensions.retry.host.omit_host_metadata.v3.OmitHostMetadataConfig
34 metadata_match:
35 filter_metadata:
36 envoy.lb:
37 key: value
38
39 clusters:
這將拒絕中繼資料中具有相符(索引鍵,值)的任何主機。
PreviousPrioritiesConfig
若要配置重試以在重試期間嘗試其他優先順序,可以使用內建的 PreviousPrioritiesConfig。
24 routes:
25 - match:
26 prefix: "/"
27 route:
28 cluster: cluster_0
29 retry_policy:
30 retry_priority:
31 name: envoy.retry_priorities.previous_priorities
32 typed_config:
33 "@type": type.googleapis.com/envoy.extensions.retry.priority.previous_priorities.v3.PreviousPrioritiesConfig
34 update_frequency: 2
35
36 clusters:
這將以在後續重試嘗試中尚未使用的優先順序為目標。update_frequency 參數會決定應該多久重新計算優先順序負載。
組合重試原則
可以組合這些外掛程式,這將排除先前嘗試過的主機和先前嘗試過的優先順序。
24 routes:
25 - match:
26 prefix: "/"
27 route:
28 cluster: cluster_0
29 retry_policy:
30 retry_host_predicate:
31 - name: envoy.retry_host_predicates.previous_hosts
32 typed_config:
33 "@type": type.googleapis.com/envoy.extensions.retry.host.previous_hosts.v3.PreviousHostsPredicate
34 host_selection_retry_max_attempts: 3
35 retry_priority:
36 name: envoy.retry_priorities.previous_priorities
37 typed_config:
38 "@type": type.googleapis.com/envoy.extensions.retry.priority.previous_priorities.v3.PreviousPrioritiesConfig
39 update_frequency: 2
40
41 clusters:
內部重新導向
Envoy 支援在內部處理 3xx 重新導向,也就是擷取可配置的 3xx 重新導向回應、合成新的請求、將其傳送到由新的路由比對指定的上游,並將重新導向的回應作為原始請求的回應傳回。原始請求的標頭和主體將在重新導向中傳送到新位置。目前尚不支援尾部。
內部重新導向是透過路由配置中的 internal_redirect_policy 欄位配置的。當重新導向處理開啟時,任何來自上游的 3xx 回應(符合 redirect_response_codes)都受制於 Envoy 處理的重新導向。
如果 Envoy 被設定為內部重新導向 HTTP 303
,並收到 HTTP 303
回應,如果原始請求不是 GET
或 HEAD
請求,則會以無主體的 HTTP GET
方式發送重新導向。否則,Envoy 會保留原始的 HTTP 方法。更多資訊請參閱 RFC 7231 第 6.4.4 節。
為了成功處理重新導向,必須通過以下檢查:
具有與 redirect_response_codes 相符的回應代碼,該代碼預設為
302
,或一組 3xx 代碼 (301
、302
、303
、307
、308
)。具有帶有有效、完整 URL 的
location
標頭。請求必須已由 Envoy 完全處理。
請求必須小於 per_request_buffer_limit_bytes 限制。
allow_cross_scheme_redirect 為
true
(預設為false
),或者下游請求的 scheme 和location
標頭的 scheme 相同。在給定的下游請求中,先前處理的內部重新導向次數不得超過請求或重新導向請求所命中的路由的 max_internal_redirects 限制。
所有 predicates 都接受目標路由。
任何失敗都會導致重新導向被傳遞到下游。
由於重新導向的請求可能會在不同的路由之間跳轉,因此重新導向鏈中的任何路由 ...
未啟用內部重新導向
或,當重新導向鏈命中該路由時,其 max_internal_redirects 小於或等於重新導向鏈的長度
或,被任何 predicates 禁止
... 都會導致重新導向被傳遞到下游。
可以使用兩個 predicates 來建立定義重新導向鏈的 DAG,分別是 previous_routes predicate 和 allow_listed_routes。具體來說,allow_listed_routes predicate 定義了 DAG 中各個節點的邊緣,而 previous_routes predicate 定義了邊緣的「已訪問」狀態,以便在需要時避免迴圈。
第三個 predicate safe_cross_scheme 可用於防止 HTTP -> HTTPS 重新導向。
一旦重新導向通過這些檢查,將通過以下方式修改傳送到原始上游的請求標頭:
將完整的原始請求 URL 放入
x-envoy-original-url
標頭中。將
Authority
/Host
、Scheme
和Path
標頭替換為Location
標頭中的值。將 response_headers_to_copy 中列出的任何標頭從重新導向回應複製到後續請求中將使用的標頭中。
然後,修改後的請求標頭將選擇新的路由,通過新的篩選器鏈發送,然後使用所有正常的 Envoy 請求清理發送到上游。
警告
請注意,HTTP 連線管理器清理 (例如清除不受信任的標頭) 只會應用一次。每個路由的標頭修改將應用於原始路由和第二個路由,即使它們相同,因此請小心設定標頭修改規則,以避免重複不需要的標頭值。
警告
請注意,沒有下游篩選器會看到觸發內部重新導向的回應。如果需要在重新導向回應和後續請求之間傳遞數據,請參閱 response_headers_to_copy。
重新導向流程的範例可能如下所示:
客戶端傳送對 http://foo.com/bar 的
GET
請求。上游 1 傳送帶有
location: http://baz.com/eep
的302
。Envoy 被設定為允許在原始路由上重新導向,並傳送新的
GET
請求至上游 2,以取得 http://baz.com/eep,並帶有額外的請求標頭x-envoy-original-url: http://foo.com/bar
。Envoy 將 http://baz.com/eep 的回應數據作為對原始請求的回應代理到客戶端。
逾時
各種可設定的逾時適用於 HTTP 連線及其組成的串流。有關重要的逾時設定的概述,請參閱 此常見問題解答條目。
HTTP 標頭映射設定
Envoy 使用連結列表數據結構維護 HTTP 標頭映射中標頭 (以及以 :
開頭的虛擬標頭) 的插入順序,當標頭數量較少時,這種數據結構速度非常快。