動態

詳情 返回 返回

圖解 Istio & Envoy 請求處理流程、超時、熔斷、指標監控 - 加入 http2 - 動態 詳情

image.png

💂 關於封面:
Tower Bridge watercolor painting by Juan Bosco

📚 摘錄説明:
本文摘自一本我在寫作中的開源書《Istio & Envoy 內幕》 中 Envoy 請求與響應調度 一節。如果説你看到的轉載圖片不清,可回到原書。《Istio & Envoy 內幕》epub 格式下載

  • 請求與響應調度

    • 相關組件
    • 相關的監控指標
    • Envoy 請求調度流程
  • 請求與響應調度時序線
  • 總結
  • 一些有趣的擴展閲讀

🎤 正式開編前。想説説寫本節的一些故事緣由。為何去研究 Envoy 的請求與響應調度?

緣起於一個客户需求,需要對 Istio 網格節點故障快速恢復做一些調研。為此,我翻閲了大量的 Istio/Envoy 文檔、大咖 Blog。看了很多很雜亂的信息:

  • 健康檢測
  • 熔斷
  • Envoy 中的各個神秘又關係千絲萬縷的 timeout 配置
  • 請求 Retry
  • TCP keepaliveTCP_USER_TIMEOUT 配置

雜亂到最後,我不得不寫個文章去梳理一下信息:Istio 網格節點故障快速恢復初探 。 但信息是梳理了,基礎原理卻沒理順。於是,我下決心去鑽研一下 Envoy 的文檔。是的,其實 Envoy 的文檔已經寫得比較細緻。只是:

  • 信息散落在一個個網頁中,無法用時序和流程的方法組織起來,構成一個有機的整體。
  • 不去了解這個整體協作關係,只是一個一個參數分開來看,是無法理性去權衡這些參數的。
  • 指標與指標,指標與參數,關係複雜
  • 而上面的關係,都可以通過請求與響應調度流程串聯起來

基於上面原因。我從文檔、參數、指標推導出以下流程。<mark>注意:暫時未完全在代碼中驗證,請謹慎參考。</mark>

本文寫於 2022-10-01

  1. 更新於 2024-06-08 : 加入 http2 相關流程,並在 draw.io 圖中加入到相關源碼的鏈接

請求與響應調度

本質上説,Envoy 就是一個代理。説起代理,第一反應應該是有以下流程的軟件/硬件:

  1. 接收來自 downstreamRequest
  2. 做一些邏輯,必要時修改 Request ,並判定upstream目的地
  3. 轉發(修改後)的 Requestupstream
  4. 如果協議是一個 Request & Reponse 式的協議(如 HTTP)

    1. 代理通常會接收upstreamResponse
    2. 做一些邏輯,必要時修改 Response
    3. 轉發 Responsedownstream

的確,這也是 Envoy 代理 HTTP 協議的概要流程。但 Envoy 還要實現很多特性:

  1. 高效的 downstream / upstream 傳輸 ➡️ 需要連接複用連接池
  2. 靈活配置的轉發目標服務策略 ➡️ 需要 Router配置策略與實現邏輯
  3. 彈性服務 (resilient micro-services)

    1. 負載均衡
    2. 突發流量的削峯平谷 ➡️ 請求排隊: pending request
    3. 應對異常 upstream、熔斷器、保護服務不雪崩 ➡️ 各種 timeout 配置、 Health checking 、 Outlier detection 、 Circuit breaking
    4. 彈性重試 ➡️ retry
  4. 可觀察性 ➡️ 無處不在的性能指標
  5. 動態編程配置接口 ➡️ xDS: EDS/LDS/...

要實現這些特性,請求與響應的流程自然不可能簡單。

💡 看到這裏,讀者可能有疑問,本節的標題叫 “請求與響應調度” ? 難度 Envoy 需要類似 Linux Kernel 調度線程一樣,去調度處理 Request 嗎?
對的,你説到點上了。

Envoy 應用了 事件驅動 設計模式。事件驅動 的程序,相對於 非事件驅動 的程序,可以用更少的線程,更靈活地控制在什麼時候做什麼任務,即更靈活的調度邏輯。且更絕的是:由於線程間共享的數據不多,線程的數據併發控制同時被大大簡化。

在本節中,事件類型最少有:

  • 外部的網絡可讀、可寫、連接關閉事件
  • 各類定時器

    • 重試定時
    • 各種超時配置定時

由於使用了無限的請求分配到有限的線程的模式,加上請求可能需要重試,所以線程一定要有一系列的邏輯,來 “排序” 什麼請求應該先處理。什麼請求由於 超時 或資源使用 超過配置上限 而應立即返回失敗。

按本書的習慣,先上圖。後面,對這個圖一步步展開和説明。

💡 互動圖書:

  • 建議用 Draw.io 打開。圖中包含大量的鏈接,鏈接到每一個組件、配置項、指標的文檔説明。
  • 雙屏,一屏看圖,一屏看文檔,是本書的正確閲讀姿勢。如果你在用手機看,那麼,忽略我吧 🤦

image.png

圖:Envoy HTTP1 請求與響應調度

用 Draw.io 打開

image.png

圖:Envoy HTTP/2 請求與響應調度

用 Draw.io 打開

相關組件

上圖是嘗試説明 Envoy 請求與響應調度 過程,以及串聯相關的組件。其中可以看到一些組件:

  • Listener - 應答 downstream 連接請求
  • HTTP Connection Manager(HCM) - HTTP 的核心組件,推動 http 流的讀取、解釋、路由(Router)
  • HCM-router - HTTP 路由核心組件,職責是:

    • 判定 HTTP 下一跳的目標 cluster,即 upsteam cluster
    • 重試
  • Load balancing - upstream cluster 內的負載均衡
  • pending request queue - 等待連接池可用連接的請求隊列
  • requests bind to connection - 已經分配到連接的請求
  • connection pool - worker 線程與 upstream host 專用的連接池
  • health checker/Outlier detection - upsteam host 健康監視,發現異常 host 並隔離。

和一些 Circuit breaking(熔斷開關) 上限條件:

  • max_retries - 最大重試併發上限
  • max_pending_requests - pending request queue 的隊列上限
  • max_request - 最大併發請求數上限
  • max_connections - upstream cluster 的最大連接上限

需要注意的是,上面的參數是對於整個 upstream cluster 的,即是所有 worker thread、upstream host 彙總的上限。

相關的監控指標

我們用類似著名的 Utilization Saturation and Errors (USE) 方法學來分類指標。

資源過載形的指標:

  • downstream_cx_overflow
  • upstream_rq_retry_overflow
  • upstream_rq_pending_overflow
  • upstream_cx_overflow

資源飽和度指標:

  • upstream_rq_pending_active
  • upstream_rq_pending_total
  • upstream_rq_active

錯誤形的指標:

  • upstream_rq_retry
  • ejections_acive
  • ejections_*
  • ssl.connection_error

信息形的指標:

  • upstream_cx_total
  • upstream_cx_active
  • upstream_cx_http*_total

由於圖中已經説明了指標、組件、配置項的關係,這裏就不再文字敍述了。圖中也提供了到指標文檔和相關配置的鏈接。

Envoy 請求調度流程

先説説請求組件流轉部分,流程圖可以從相關的文檔推理為(未完全驗證,存在部分推理):

image.png

圖:Envoy 請求調度流程圖
用 Draw.io 打開

image.png

圖:Envoy HTTP/2 請求調度流程圖
用 Draw.io 打開

請求與響應調度時序線

本節開頭説了,寫本節的直接緣由是: 需要對 Istio 網格節點故障快速恢復做一些調研。快速恢復 的前提是:

  • 對已經發送到 故障 upstream host 或綁定到 故障 upstream host 的請求,快速響應失敗
  • Outlier detection / health checker 識別出 故障 upstream host ,並把它移出負載均衡列表

所有問題都依賴於一個問題:如何定義和發現 upstream host 出了故障?

  • 網絡分區或對端崩潰或負載過高

    • 大多數情況下,分佈式系統只能通過超時來發現這種問題。所以,要發現 故障 upstream host故障 request ,需要配置
  • 對端有響應,L7 層的失敗(如 HTTP 500),或 L3 層的失敗(如 TCP REST/No router to destination/ICMP error)

    • 這是可以快速發現的失敗

對於 網絡分區或對端崩潰或負載過高,需要 timeout 發現的情況,Envoy 提供了豐富的 timeout 配置。豐富到有時讓人不知道應該用哪個才是合理的。甚至配置一不小心,就配置出一些邏輯上長短與實現設計矛盾的值。所以,我嘗試用理清楚 請求與響應調度時序線 ,然後看相關 timeout 配置關聯到這個時間線的哪個點,那麼整個邏輯就清楚了。配置也更容易合理化了。

下圖是請求與響應的時序線,以及相關的 timeout 配置與產生的指標,以及它們的聯繫。

image.png

圖:Envoy 請求與響應時序線
用 Draw.io 打開

簡單説明一下時間線:

  1. 如果 downstream 複用了之前的連接,可以跳過 2 & 3
  2. downstream發起 新連接(TCP 握手)
  3. TLS 握手
  4. Envoy 接收 downstream request header & body
  5. Envoy 執行路由(Router)規則,判定下一跳的 upstream cluster
  6. Envoy 執行 Load Balancing 算法 ,判定下一跳的 upstream cluster 的 upstream host
  7. 如果 Envoy 已經有空閒連接到 upstream host,則跳過 8 & 9
  8. Envoy 向 upstream host 發起新連接(TCP 握手)
  9. Envoy 向 upstream host 發起TLS 握手
  10. Envoy 向 upstream host 轉發送 requst header & body
  11. Envoy 接收 upstream host 響應的 response header & body
  12. upstream host 連接開始 idle
  13. Envoy 向 downstream 轉發送 response header & body
  14. downstream host 連接開始 idle

相應地,圖中也標註了相關超時配置與時間線步驟的關係,從開始計時順序排列如下

  • max_connection_duration
  • transport_socket_connect_timeout

    • 指標 listener.downstream_cx_transport_socket_connect_timeout
  • request_headers_timeout
  • requst_timeout
  • Envoy 的 route.timeout 即 Istio 的 Istio request timeout(outbound)

    注意,這個超時值是把 請求處理時實際的 retry 的總時間也算上的。

    • 指標 cluster.upstream_rq_timeout
    • 指標 vhost.vcluster.upstream_rq_timeout
  • max_connection_duration
  • connection_timeout

    • 指標 upstream_cx_connect_timeout
  • transport_socket_connect_timeout
  • httpprotocoloptions.idle_timeout

總結

想要 Envoy 在壓力與異常情況下,有個比較符合預期的表現,需要給 Envoy 一些合理於具體應用環境與場景的配置。而要配置好這堆參數的前提,是對相關處理流程與邏輯的洞察。 上面把 請求與響應調度請求與響應調度時序線 都過了一遍。希望對了解這些方面有一定的幫助。

不只是 Envoy ,其實所有做代理的中間件,可能最核心的東西都在這一塊了。所以,不要期望一下把知識完全吃透。這裏,也只是希望讓讀者在這些流程上,有一個線索,然後通過線索去學習,方可不迷失方向。

一些有趣的擴展閲讀

  • https://www.istioworkshop.io/09-traffic-management/06-circuit...
  • https://tech.olx.com/demystifying-istio-circuit-breaking-27a6...

Add a new 評論

Some HTML is okay.