Server-Speaks-First 有點坑,Linkerd 2.10 中的協議檢測和不透明埠

為少發表於2021-08-10

協議檢測(Protocol detection),顧名思義,允許 Linkerd 自動檢測 TCP 連線中使用的協議。 Linkerd 的設計原則之一是“just work”,協議檢測是 Linkerd 如何實現這一目標的重要組成部分。

什麼是協議檢測?

簡而言之,協議檢測是通過檢查連線上的流量來確定 TCP 連線上使用的協議的能力。

Linkerd 使用 Protocol detection 來避免要求使用者指定協議。 Linkered 的代理不需要使用者配置每個埠使用的協議,而是簡單地執行協議檢測來回答問題。

LinkerdProtocol detection 通過檢視客戶端連線的前幾個位元組來獲取有關流量的資訊來工作。 這種實現有一些後果,我們將在下面介紹。

但首先,讓我們首先回答為什麼 Linkerd 關心任何協議的問題。

可觀察性、可靠性和安全性

我們通常將 Linkerd 的廣泛功能分為三類:可觀察性(Observability)、可靠性(reliability)和安全性(security)。 瞭解連線(connection)上使用的協議是每個類別的基礎。

可觀察性

Linkerd 可觀察性功能的核心是流量檢測。 這種儀器需要了解正在使用的協議,因為協議的知識可以提供豐富的指標。 例如,知道連線正在使用 HTTPLinkerd 就可以解析請求、響應和響應程式碼,並報告響應延遲、請求量和錯誤率等指標。 這些指標非常有價值,以至於它們成為谷歌 SRE 書中所謂的“黃金訊號”的一部分。 另一方面,如果 Linkerd 只知道連線是 TCP,則它僅限於記錄非常基本的資訊,例如讀取和寫入的位元組數——無法進一步解釋位元組。

Linkerd 可觀察特性的核心是流量的測量。這種檢測需要理解正在使用的協議,因為對協議的瞭解可以提供豐富的度量。例如,知道一個連線正在使用 HTTP,就允許 Linkerd 解析請求、響應和響應程式碼,並報告響應延遲、請求量和錯誤率等指標。這些指標非常有價值,它們是谷歌的 SRE 書中所謂的“黃金訊號”的一部分。另一方面,如果 Linkerd 只知道一個連線是 TCP,那麼它只能記錄非常基本的資訊,比如讀取和寫入的位元組數——沒有進一步解釋位元組的能力。

安全

雙向 TLS (mTLS)Linkerd 的核心功能。從 Linkerd 2.9 開始,網狀端點(meshed endpoints)之間的所有 TCP 流量預設由 Linkerd 代理進行 mTLS。 (有一些警告 - 請參閱下面有關 skip-ports 的部分。)

在這裡,再次瞭解連線的協議至關重要。例如,如果連線已經是 TLS 的(例如,通過應用程式),則沒有理由重新 TLS。(嚴格來說,TLS 是一種傳輸層協議,而不是像 HTTP 那樣的應用層協議,但就本文而言,兩者之間的區別並不重要。)

可靠性

最後,瞭解底層連線的協議允許 Linkerd 提供複雜的可靠性功能。 這裡的一個例子是負載平衡。 在不知道連線協議的情況下,Linkerd 僅限於平衡連線(balancing connections):一旦與伺服器建立了 TCP 連線,它就無法進一步操作該連線。

但是,如果 Linkerd 知道連線是 HTTP,它可以從連線平衡(connection balancing)轉移到請求平衡(request balancing)。Linkerd 將建立一個跨端點的連線池,並平衡這個池中的請求。 由於它現在可以訪問 requestsresponsesLinkerd 在平衡請求方面可以非常複雜; 事實上,它根據每個可能端點的最近效能(使用稱為“指數加權移動平均(exponentially weighted moving average)”或 EWMA 的指標)來平衡請求,以避免從慢速端點引起尾部延遲(tail latency)。

( Linkerd 也是 Kubernetes 中負載平衡 gRPC 連線的一個簡單解決方案。)

當協議檢測失敗時

雖然協議檢測旨在允許 Linkerd “just work”,但在某些情況下它不能:臭名昭著的伺服器優先協議(server-speaks-first)。 這些協議(包括 MySQLSMTP)通過讓客戶端建立連線然後等待伺服器響應來工作。從 TCP 的角度來看,這是一種完全合法的行為,但這意味著 Linkerd 無法檢測到協議,因為相關資訊來自伺服器,而不是客戶端。

(為什麼不簡單地使用伺服器的位元組來檢測協議?因為在檢測協議的時候,Linkerd 甚至還沒有建立到伺服器的連線。選擇與哪個伺服器對話是負載均衡器的一個功能,而使用哪個負載均衡器是協議的一個功能。這是一個 delicious、帶有 TCP-flavored 的“先有雞還是先有蛋(chicken-and-egg)”問題。)

為了避免這種情況,Linkerd 引入了 skip-inbound-portsskip-outbound-ports 配置選項。 這些選項指示 Linkerd 通過修改 Linkerd 用於通過其 sidecar 代理連線 podiptables 規則來完全繞過某些埠的代理。例如,將 annotation config.linkerd.io/skip-outbound-ports: 3306 新增到工作負載的 PodSpec 指示 Linkerd 建立一個 iptables 規則,以確保 Linkerd 代理永遠不會處理到埠 3306MySQL 埠)的任何流量 . 同樣,annotation config.linkerd.io/skip-inbound-ports: 3306 將編寫一個 iptables 規則,以便代理永遠不會處理髮送給它的 MySQL 流量。

Skip Ports 配置

這些選項為 protocol detection 無法處理 server-speaks-first 協議提供了一種解決方法。 然而,它們有一個明顯的缺點:因為它們完全繞過 Linkerd 代理,Linkerd 無法應用 mTLS 或捕獲這些埠的任何指標。

Linkerd 2.10 中的不透明埠和改進的協議檢測

為了解決 skip-ports 的不足,在 2.10 版本中,Linkerd 將新增不透明埠(opaque ports)的概念(以及相應的 opaque-ports annotation)。不透明埠就是 Linkerd 將代理而不執行協議檢測的埠。雖然這種方法仍然需要配置,但將埠標記為不透明允許 Linkerd 應用 mTLS 並報告 TCP-level metrics —— 這比完全跳過它是一個很大的改進。

Opaque Ports 配置

Linkerd 2.10 還將通過使其“fail open”來改進協議檢測的工作方式:如果協議檢測程式碼在 10 秒後沒有看到客戶端位元組,它會將連線視為 TCP 連線並繼續,而不是像 2.9 那樣失敗 . 這意味著不使用 opaque-ports(或 skip-ports)annotating server-speaks-first 埠的最壞情況行為是 10 秒的連線時間延遲,而不是連線失敗。

總結

Protocol detectionLinkerd 最強大的功能之一,也是 Linkerd “just works” 原則的基礎。雖然協議檢測不是萬靈藥,但 Linkerd 2.10 中引入的 opaque-ports 應該解決早期 skip-ports 特性的大部分缺點,並允許 Linkerd 使用者在整個 Kubernetes 環境中擴充套件 mTLS,而不管協議是什麼。

我是為少
微信:uuhells123
公眾號:黑客下午茶
加我微信(互相學習交流),關注公眾號(獲取更多學習資料~)

相關文章