Kubernetes使用OkHttp客戶端進行網路負載平衡

Kubernetes使用OkHttp客戶端進行網路負載平衡

兩個來源Pod向六個目標Pod發送請求,可以清楚看到請求分佈在目標Pod之間存在不均衡。在本文中,我將討論我們採取的措施來負載平衡這組服務和Pod。

在一次內部Java服務稽核中,我們發現有些請求沒有在Kubernetes(K8s)網路上正確實現負載平衡。導致我們深入研究的問題是HTTP 5xx錯誤率的急劇上升,由於CPU使用率非常高,垃圾收集事件的數量很多以及超時,但這僅發生在一些特定的Pod中。

這種情況並非在所有情況下都可見,因為它影響到多Pod服務,且來源Pod和目標Pod的數量不同。在本篇部落格文章中,我將討論我們採取的措施來負載平衡這組服務和Pod。

在我們的部署中,請求在Pod之間是如何均衡的?

兩個來源Pod向六個目標Pod發送請求。

可以清楚看到請求分佈在目標Pod之間存在不均衡。

但為什麼會這樣呢?

K8s負載平衡器(IPVS代理模式)的預設負載平衡調度程式設定為輪詢(round robin)。IPVS提供了更多的選項來均衡​​流量到Pod後端。在測試這些選項時,我們發現當涉及到我們的服務時,不管配置如何,行為都相同,這些服務之間使用內部路由進行通訊。

到底發生了什麼事?K8s中的IPVS根據連接來平衡流量,這在大多數情況下都表現得相當不錯。我們的服務使用OkHttp作為相互通訊的HTTP客戶端。我們的問題與這個HTTP客戶端的行為方式有關。使用預設配置,它會創建到伺服器的連接,如果您不想在程式碼中明確關閉連接,因為這太昂貴,那麼它會保持並重新建立到先前合作夥伴的連接。這意味著客戶端嘗試保持與目標的連接,並透過該特定連接發送請求。通常情況下,它會創建1:1的連接,這在K8s方面沒有均衡。

怎麼辦?

如果您需要擴充或希望使您的服務得到適當的負載平衡,您需要在用戶端端更新設定。OkHttp提供了ConnectionPool功能。當使用ConnectionPool選項時,連接將在有限的時間段內建立,然後重複設定一個新的連接,因此IPVS可以進行負載平衡,因為它有大量的新連接,應該根據IPVS調度程序路由到目標。基本上,它的工作方式類似於機關槍而不是雷射光束。

我們在發布此更新後的效果如何?

使用更新的HTTP客戶端和預設IPVS調度程式在多Pod服務之間實現了負載平衡的連線。

到底做了什麼改變?

我們進行了大量的測試,使用各種配置來測量回應時間和效能開銷,以確保負載平衡。下面是主要的程式碼更改,看起來沒有明顯的效能開銷。

程式碼更改範例

有一個選項可以設定調度程序,以便能夠並行發送更多的請求。在我們的情況下,這最終會建立一組最近關閉的連接,然後繼續只使用一個連接。此外,我們試圖防止過於頻繁地打開新連接,因為執行請求比打開新連接要少要求得多。

結果如何?

網路和資源的使用現在比以前更加平衡- 沒有巨大或持續很長時間的峰值,也沒有出現只影響部署中某些Pod的「嘈雜鄰居」效應。現在幾乎所有的Pod都以幾乎相同的方式被利用,因此我們能夠減少我們的部署中的Pod數量。我們知道這並不完美,但對於我們的用例來說已經足夠好,因為它不會為服務或IPVS負載平衡器帶來明顯的效能開銷。

現在的Pod上的請求負載平衡

結論

定期進行徹底的服務審計是有益的,因為它可以揭示未來對所有服務有益的優化點,並在解決那些本應該立即運行的功能的奇怪症狀時為您節省時間。此外,花些時間查看文檔,測試,討論並了解在使用客戶端庫時關於連接設定和處理的預設設定的影響,以確保它們將按照您的預期行事。