新聞中心
本文轉(zhuǎn)載自微信公眾號「架構(gòu)技術(shù)漫談」,作者LA0WAN9。轉(zhuǎn)載本文請聯(lián)系架構(gòu)技術(shù)漫談公眾號。

一般來說,在 K8S 下部署服務(wù)是很簡單的事兒,但是如果部署的是一個 gRPC 服務(wù)的話,那么稍不留神就可能掉坑里,個中緣由,且聽我慢慢道來。
在 K8S 下部署服務(wù),缺省會被分配一個地址(也就是 ClusterIP[1]),客戶端的請求會發(fā)送給它,然后再通過負載均衡轉(zhuǎn)發(fā)給后端某個 pod:
ClusterIP
如果是 HTTP/1.1 之類的服務(wù),那么 ClusterIP 完全沒有問題;但是如果是 gRPC 服務(wù),那么 ClusterIP 會導(dǎo)致負載失衡,究其原因,是因為 gRPC 是基于 HTTP/2 的,多個請求在一個 TCP 連接上多路復(fù)用,一旦 ClusterIP 和某個 pod 建立了 gRPC 連接后,因為多路復(fù)用的緣故,所以后續(xù)其它請求也都會被轉(zhuǎn)發(fā)給此 pod,結(jié)果其它 pod 則完全被忽略了。
看到這里,有的讀者可能會有疑問:HTTP/1.1 不是實現(xiàn)了基于 KeepAlive 的連接復(fù)用么?為什么 HTTP/1.1 的復(fù)用沒問題,而 HTTP/2 的復(fù)用就有問題?答案是 HTTP/1.1 的 復(fù)用是串行的,當請求到達的時候,如果沒有空閑連接那么就新創(chuàng)建一個連接,如果有空閑連接那么就可以復(fù)用,同一個時間點,連接里最多只能承載有一個請求,結(jié)果是 HTTP/1.1 可以連接多個 pod;而 HTTP/2 的復(fù)用是并行的,當請求到達的時候,如果沒有連接那么就創(chuàng)建連接,如果有連接,那么不管其是否空閑都可以復(fù)用,同一個時間點,連接里可以承載多個請求,結(jié)果是 HTTP/2 僅僅連接了一個 pod。
了解了 K8S 下 gRPC 負載均衡問題的來龍去脈,我們不難得出解決方案:
在 Proxy 中實現(xiàn)負載均衡:采用 Envoy 做代理,和每臺后端服務(wù)器保持長連接,當客戶端請求到達時,代理服務(wù)器依照規(guī)則轉(zhuǎn)發(fā)請求給后端服務(wù)器,從而實現(xiàn)負載均衡。
Proxy
在 Client 中實現(xiàn)負載均衡:把服務(wù)部署成 headless service[2],這樣服務(wù)就有了一個域名,然后客戶端通過域名訪問 gRPC 服務(wù),DNS resolver 會通過 DNS 查詢后端多個服務(wù)器地址,然后通過算法來實現(xiàn)負載均衡。
Client
兩種方案的優(yōu)缺點都很明顯:Proxy 方案結(jié)構(gòu)清晰,客戶端不需要了解后端服務(wù)器,對架構(gòu)沒有侵入性,但是性能會因為存在轉(zhuǎn)發(fā)而打折扣;Client 方案結(jié)構(gòu)復(fù)雜,客戶端需要了解后端服務(wù)器,對架構(gòu)有侵入性,但是性能更好。
參考資料
[1]ClusterIP: https://kubernetes.io/docs/concepts/services-networking/service/
[2]headless service: https://kubernetes.io/docs/concepts/services-networking/serv
網(wǎng)頁標題:淺談K8S下gRPC負載均衡問題
網(wǎng)頁網(wǎng)址:http://www.5511xx.com/article/ccioecp.html


咨詢
建站咨詢
