淺談長連接負載均衡
- 2022 年 10 月 28 日
- 筆記
hello,大家好,我是小樓,終於忙完了一陣,今天來更新一篇長連接的負載均衡問題。
首先說明下,長連接我不是專業的,只是在工作上有一點點的接觸,分享也是基於一點點的經驗和一些思考,如有出入,歡迎私聊。
長連接介紹
說長連接,與之對應的是短連接,關於這兩個的介紹網上比較多,這裡只用一個表格來總結下他們的工作流程、優缺點、適用場景等:
短連接 | 長連接 | |
---|---|---|
流程 | 建立連接 -> 傳輸數據 -> 關閉連接 | 建立連接 -> 傳輸數據 -> 傳輸數據 ->… -> 關閉連接 |
優點 | 實現簡單 | 耗時(DNS解析、TCP 握、揮手)少;能實現服務端推送 |
缺點 | 耗時(DNS解析、TCP 握、揮手)多 | 需要管理連接,實現複雜;連接多時服務端消耗大 |
場景 | 單客戶端不頻繁操作但客戶端數量多;如 Web 服務 | 單客戶端頻繁操作;如數據庫、需要推送能力的服務 |
長連接負載均衡
長連接為什麼需要負載均衡
長連接單機的連接數是存在上限的。
存在上限的原因,可能有同學認為是單機的端口數限制,也就是經常聽到的問題「一台服務器最多能支撐多少個 TCP 連接?」
有人回答「65535」,其實不然,如果硬件限制不考慮,單機能撐200多萬億個 TCP 連接,但這太理想,現實是撐個百萬連接還是可以的。具體怎麼回事,可以戳飛哥這篇文章《漫畫 | 一台Linux服務器最多能支撐多少個TCP連接?》了解詳細。
從經驗來看,CPU 和 內存是限制連接數的主要原因。
內存不必多說,每個連接的保持都要佔用一點內存,一條空連接,也要佔用幾 KB 的內存,如果再塞點數據,幾百 KB 到幾 MB 也是常有的事,按一條連接 1MB 算,一台 128GB 內存的物理機能撐十幾萬的連接。
其次是 CPU,我們上面說了長連接的場景一般是單個客戶端操作頻繁,這就會導致每增加一條連接,CPU 消耗就增加一些,一般單機能撐十萬的連接,已經算是可以了。
基於單機性能和高可用容災的考慮,生產環境長連接服務通常會部署多個節點,為此,我們需要考慮長連接服務的負載均衡問題。
長連接負載均衡粒度
與短連接每次請求都做負載均衡策略不同,長連接不光有請求粒度的負載均衡,還有連接粒度的負載均衡。
請求粒度負載均衡的實現方式是一個客戶端與每個服務端都建立連接,發送請求時按照某種負載均衡策略選擇一個服務端進行請求;連接粒度的負載均衡則是客戶端在建立連接時按照某種負載均衡策略挑選一個節點進行建連,後續請求都發往這個節點。
如何選擇主要是考量單個服務端可能的連接數量,如果連接數遠不是瓶頸的時候(個人認為萬級以下),可考慮請求粒度,否則連接粒度的負載均衡策略更佳。
舉個例子,Dubbo 一個 Provider 節點和來自訂閱 Consumer 的所有節點都建立了連接,前提是 Dubbo 一個 Provider 基本不太會可能被幾萬個節點消費,所以 Dubbo 可以做請求粒度的長連接負載均衡。但如果是 Nacos,所有需要服務發現的機器都要和 Nacos 服務端建立連接,長連接數量就和公司服務器數量級相關,規模大的情況,幾萬、上十萬、百萬也是有可能的,所以如果 Nacos 也像 Dubbo 那樣設計,就無法支撐大規模服務發現了。
連接粒度的負載均衡
對於長連接,連接粒度的負載均衡問題遇到的更多,所以這裡着重說明下。
連接數均衡
由於連接建立之後,除非異常不會斷開,所以問題就來了,如果某一個節點的連接數相比較其他節點要多出很多,這種就屬於不均衡了。出現這種問題的情況最常見的就是服務端發佈(重啟)。重啟時服務不可用,該節點原先的連接會斷開,找到存活的節點進行連接,當這台服務起來時,它的連接數將非常少。如果是一輪發佈,最先發佈的機器最後連接數最多,最後發佈的連接數最少。
這種情況下,我們可以調整建連的負載均衡算法為最小連接數模式,當服務重啟完成後,後續的連接就能全部連接到此節點。
但這個方法並不總是奏效,因為服務在重啟時,斷開的連接已經和其他節點建立了連接。
這時我們可能需要額外的均衡手段,如定時從全局視角看各個節點的連接數是否均衡,如果不均衡則要斷開最多連接的節點,直到平衡。
這裡我們的客戶端需要對連接的斷開處理特別小心,當然我覺得這是必須的。
但也要說明一點,如果連接不是長時間保持的,額外的均衡手段可能就不需要了,等一會就自然平衡了。這種發生在什麼情況呢?比如公網的長連接,客戶端的網絡情況沒內網那麼好,經常斷開連接,這就相當於幫我們自動平滑連接了。
如果是內網服務,連接能一直保持,額外的平衡手段就顯得有必要了。
服務器規格不同
我們通常為了單機能保持更多的長連接,一般會選用物理機部署服務,有時候各個物理機規格不統一,如果我們的均衡手段一視同仁,每個節點連接數差不多,規格差的服務器可能壓力就比其他機器大。
所以建連的負載均衡算法和額外的均衡手段也要考慮服務器規格,可以簡單地把服務器規格與當前的連接數抽象為一個權重,客戶端建連時加權再選擇。
擴容無效問題
我們的長連接服務理應是可水平擴容的,連接數變多,加機器就可以,我們的設計大多也是如此。
但有時候可能不小心,導致水平擴容無效。
舉個例子,還是註冊中心,假設有3個節點的註冊中心集群,此時有 1w 個客戶端連上來,訂閱了各種各樣的服務,由於客戶端的數量遠遠大於註冊中心節點,所以基本可以認為每個註冊中心節點訂閱的服務是差不多的,近似每個服務的變更,每個註冊中心節點都要處理,CPU 消耗自然就多了。如果把註冊中心節點擴容為5台,其實每台服務只是少了一點連接,但依然每個註冊中心節點還是近乎要處理所有的服務變更。
這種情況下就要審視長連接服務設計的是否合理,一般採取分層的思想,長連接這層服務只專註推送,一般稱為通道層或者 session 層,它並不複雜複雜的計算邏輯。
如果設計有問題,短時間又沒法修改,可以試試按照服務訂閱者的名字路由到特定的服務端節點,保證同一個 Conusmer 只連同一個註冊中心節點,這樣某服務變更時,該節點只需要計算一次,就可以推送給所有 Conusmer,運氣好的話,其他節點都不用計算。
結語
本文介紹了長連接與短連接的特點,為什麼需要做長連接負載均衡,以及幾個長連接負載均衡的問題和解法,相對來說還是比較通俗易懂,希望對大家有所幫助。
搜索關注微信公眾號”捉蟲大師”,後端技術分享,架構設計、性能優化、源碼閱讀、問題排查、踩坑實踐。