Server-Speaks-First 有點坑,Linkerd 2.10 中的協議檢測和不透明端口
- 2021 年 8 月 10 日
- 筆記
協議檢測(Protocol detection
),顧名思義,允許 Linkerd
自動檢測 TCP
連接中使用的協議。 Linkerd
的設計原則之一是「just work」
,協議檢測是 Linkerd
如何實現這一目標的重要組成部分。
什麼是協議檢測?
簡而言之,協議檢測是通過檢查連接上的流量來確定 TCP 連接上使用的協議的能力。
Linkerd
使用 Protocol detection
來避免要求用戶指定協議。 Linkered
的代理不需要用戶配置每個端口使用的協議,而是簡單地執行協議檢測來回答問題。
Linkerd
的 Protocol detection
通過查看客戶端連接的前幾個位元組來獲取有關流量的信息來工作。 這種實現有一些後果,我們將在下面介紹。
但首先,讓我們首先回答為什麼 Linkerd
關心任何協議的問題。
可觀察性、可靠性和安全性
我們通常將 Linkerd
的廣泛功能分為三類:可觀察性(Observability
)、可靠性(reliability
)和安全性(security
)。 了解連接(connection
)上使用的協議是每個類別的基礎。
可觀察性
Linkerd
可觀察性功能的核心是流量檢測。 這種儀器需要了解正在使用的協議,因為協議的知識可以提供豐富的指標。 例如,知道連接正在使用 HTTP
,Linkerd
就可以解析請求、響應和響應代碼,並報告響應延遲、請求量和錯誤率等指標。 這些指標非常有價值,以至於它們成為谷歌 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
將建立一個跨端點的連接池,並平衡這個池中的請求。 由於它現在可以訪問 requests
和 responses
,Linkerd
在平衡請求方面可以非常複雜; 事實上,它根據每個可能端點的最近性能(使用稱為「指數加權移動平均(exponentially weighted moving average
)」或 EWMA
的指標)來平衡請求,以避免從慢速端點引起尾部延遲(tail latency
)。
( Linkerd
也是 Kubernetes
中負載平衡 gRPC
連接的一個簡單解決方案。)
當協議檢測失敗時
雖然協議檢測旨在允許 Linkerd
「just work」
,但在某些情況下它不能:臭名昭著的服務器優先協議(server-speaks-first
)。 這些協議(包括 MySQL
和 SMTP
)通過讓客戶端建立連接然後等待服務器響應來工作。從 TCP
的角度來看,這是一種完全合法的行為,但這意味着 Linkerd
無法檢測到協議,因為相關信息來自服務器,而不是客戶端。
(為什麼不簡單地使用服務器的位元組來檢測協議?因為在檢測協議的時候,Linkerd
甚至還沒有建立到服務器的連接。選擇與哪個服務器對話是負載均衡器的一個功能,而使用哪個負載均衡器是協議的一個功能。這是一個 delicious
、帶有 TCP-flavored
的「先有雞還是先有蛋(chicken-and-egg
)」問題。)
為了避免這種情況,Linkerd
引入了 skip-inbound-ports
和 skip-outbound-ports
配置選項。 這些選項指示 Linkerd
通過修改 Linkerd
用於通過其 sidecar
代理連接 pod
的 iptables
規則來完全繞過某些端口的代理。例如,將 annotation
config.linkerd.io/skip-outbound-ports: 3306
添加到工作負載的 PodSpec
指示 Linkerd
創建一個 iptables
規則,以確保 Linkerd
代理永遠不會處理到端口 3306
(MySQL
端口)的任何流量 . 同樣,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 detection
是 Linkerd
最強大的功能之一,也是 Linkerd
「just works」
原則的基礎。雖然協議檢測不是萬靈藥,但 Linkerd 2.10
中引入的 opaque-ports
應該解決早期 skip-ports
特性的大部分缺點,並允許 Linkerd
使用者在整個 Kubernetes
環境中擴展 mTLS
,而不管協議是什麼。
我是為少
微信:uuhells123
公眾號:黑客下午茶
加我微信(互相學習交流),關注公眾號(獲取更多學習資料~)