WebSocket負(fù)載均衡實(shí)現(xiàn)
優(yōu)化資源使用、最大化吞吐量、最小化響應(yīng)時間并避免任何單個資源的過載.
WebSocket是一種在單個TCP連接上進(jìn)行全雙工通訊的協(xié)議。它允許服務(wù)器主動向客戶端推送信息,客戶端和服務(wù)器之間的連接持久化,使得雙方可以實(shí)現(xiàn)實(shí)時的數(shù)據(jù)傳輸。WebSocket廣泛應(yīng)用于需要實(shí)時通信的應(yīng)用場景,如在線聊天、實(shí)時通知、游戲等。
負(fù)載均衡技術(shù)可以將客戶端的請求分發(fā)到多個服務(wù)器上,從而平衡服務(wù)器的負(fù)載,提高系統(tǒng)的整體性能和可靠性。常見的WebSocket負(fù)載均衡算法包括:
輪詢(Round Robin):按順序?qū)⒄埱蠓峙浣o各個服務(wù)器,確保每臺服務(wù)器都能處理一定數(shù)量的請求。
加權(quán)輪詢(Weighted Round Robin):在輪詢的基礎(chǔ)上,根據(jù)服務(wù)器的性能或負(fù)載情況設(shè)置權(quán)重,將請求優(yōu)先分配給性能較好或負(fù)載較低的服務(wù)器。
最小連接數(shù)(Least Connections):將請求分配給當(dāng)前連接數(shù)最少的服務(wù)器,以確保所有服務(wù)器上的連接數(shù)盡可能平衡。
哈希算法(Hashing):根據(jù)請求的特定屬性(如IP地址、用戶ID等)計(jì)算哈希值,將相同哈希值的請求分配給同一臺服務(wù)器,以實(shí)現(xiàn)請求的精準(zhǔn)分發(fā)。
在管理大型系統(tǒng)時,負(fù)載均衡問題一直是一個熱門問題。負(fù)載均衡旨在優(yōu)化資源使用、最大化吞吐量、最小化響應(yīng)時間并避免任何單個資源的過載,因此解決此問題對于性能至關(guān)重要。在本文中,我們將了解該問題的可能解決方案。
為了更好地理解 WS 負(fù)載平衡,讓我們更深入地了解 TCP 套接字的背景。默認(rèn)情況下,單個服務(wù)器可以處理 65,536 個套接字連接,因?yàn)樗强捎?TCP 端口的最大數(shù)量。因此,由于 WS 連接具有 TCP 性質(zhì),并且每個 WS 客戶端都占用一個端口,因此我們可以肯定地說 websocket 連接的數(shù)量也是有限的。
實(shí)際上,這只是半真半假。服務(wù)器可以處理每個 IP 地址的 65,536 個套接字。因此,可以通過向服務(wù)器添加額外的網(wǎng)絡(luò)接口來輕松擴(kuò)展數(shù)量。同時,跟蹤服務(wù)器上存在的連接數(shù)量非常重要。
一旦超過限制,其他 TCP 連接可能會遇到很多問題(例如,無法通過 ssh 連接到服務(wù)器)。因此,在應(yīng)用程序代碼中限制每個節(jié)點(diǎn)的 WS 連接是一個好主意。當(dāng)我們處理 websockets 時,我們在應(yīng)用程序中做同樣的事情。
一旦我們了解了主要限制和克服它的方法,我們就可以繼續(xù)進(jìn)行負(fù)載均衡。下面我將描述我們在其中一個項(xiàng)目中嘗試的 3 種方法。請注意,所有系統(tǒng)部件都已部署到 AWS,一些提示和提示僅適用于 Amazon 配置。設(shè)計(jì)WebSocket負(fù)載均衡方案時,可以考慮以下幾個方面:
選擇合適的負(fù)載均衡器:根據(jù)實(shí)際需求選擇合適的負(fù)載均衡器,如Nginx、HAProxy等,它們支持WebSocket協(xié)議并提供豐富的負(fù)載均衡策略。
配置粘性會話:在負(fù)載均衡器中配置粘性會話,以確保同一客戶端的WebSocket連接在多次請求中始終被分發(fā)到同一臺服務(wù)器上。
監(jiān)控和日志:配置監(jiān)控和日志系統(tǒng),以便實(shí)時監(jiān)控服務(wù)器的負(fù)載情況和WebSocket連接的狀態(tài),及時發(fā)現(xiàn)并解決問題。
故障恢復(fù)機(jī)制:設(shè)計(jì)故障恢復(fù)機(jī)制,以便在服務(wù)器發(fā)生故障時能夠自動將連接和消息流量轉(zhuǎn)移到其他服務(wù)器上,保證系統(tǒng)的持續(xù)運(yùn)行。
ELB方案
實(shí)施負(fù)載均衡的最簡單方法是使用 AWS 提供的 Elastic Load Balancer??梢詫?ELB 切換到 TCP 模式,從而實(shí)現(xiàn)任何類型的 TCP 連接的負(fù)載均衡,包括 websockets。這種方法提供:
LB 的自動故障轉(zhuǎn)移
負(fù)載均衡節(jié)點(diǎn)的自動擴(kuò)展
設(shè)置非常簡單
基本上,對于大多數(shù)常見情況,這是一個很好的解決方案,直到您的負(fù)載出現(xiàn)飛濺增長。在這種情況下,ELB 變得太慢,無法建立新連接??梢月?lián)系 Amazon 并要求他們“預(yù)熱”ELB,但當(dāng)我們需要快速建立數(shù)千個 WS 連接時,出于負(fù)載測試目的,而對于我們的客戶來說,由于系統(tǒng)的可用性,這對我們來說不是一個選擇。
軟件負(fù)載均衡器
我們已經(jīng)嘗試將 HAProxy 作為負(fù)載均衡器。但是要使 HAProxy 正常工作,應(yīng)該記住我們上面討論的端口限制問題。要使 HAProxy 處理超過 65k 個連接,我們應(yīng)該完成以下步驟:
1. 創(chuàng)建一堆私有 IP 地址。為此,請選擇您的 Amazon 實(shí)例 -> 操作 -> 聯(lián)網(wǎng) -> 管理私有 IP 地址。即添加了 3 個 IP 地址:192.168.1.1、192.168.1.2、192.168.1.3。請記住,IP 應(yīng)該與你的真實(shí)應(yīng)用程序服務(wù)器位于同一子網(wǎng)中;
2. 通過 SSH 連接到您的 HAProxy 實(shí)例并運(yùn)行以下命令:
$> ifconfig eth0:1 192.168.1.1
$> ifconfig eth0:2 192.168.1.2
$> ifconfig eth0:3 192.168.1.3
這將向?qū)嵗砑?3 個虛擬網(wǎng)絡(luò)接口;
3. 配置 HAProxy。以下是文件中接受 WS 連接的 3 個 Erlang 節(jié)點(diǎn)的部分。haproxy.cfg
listen erlang_front :8888
mode http
balance roundrobin
timeout connect 1s
timeout queue 5s
timeout server 3600s
option httpclose
option forwardfor
server erlang-1 192.168.0.1:8888 source 192.168.1.1
server erlang-2 192.168.0.2:8888 source 192.168.1.2
server erlang-3 192.168.0.3:8888 source 192.168.1.3
現(xiàn)在 HAProxy 可以處理超過 65,536 個 websocket 連接,并且可以通過添加虛擬網(wǎng)絡(luò)接口輕松增加連接限制。此外,它可以相當(dāng)快速地建立新的連接。
盡管存在以下缺點(diǎn),但這種方法似乎是可行的:
故障轉(zhuǎn)移 HAProxy 實(shí)例應(yīng)使用以下工具手動設(shè)置keepalived;
每當(dāng)添加新的 Erlang 節(jié)點(diǎn)時,都必須做一些事情來重新配置 HAProxy;
隨著連接數(shù)量的增加,沒有選項(xiàng)可以水平擴(kuò)展 HAProxy。我們只有垂直選項(xiàng)可用,因此當(dāng)我們有越來越多的活躍用戶時,我們應(yīng)該為 HAProxy(和 HAProxy 鏡像節(jié)點(diǎn))獲得越來越昂貴的實(shí)例。
我們對這些缺點(diǎn)沒問題,但實(shí)施了更簡單的解決方案。這是可能的,因?yàn)槲覀円呀?jīng)實(shí)現(xiàn)了一些代碼,并且我們的系統(tǒng)設(shè)計(jì)允許我們使用自定義方法。
自定義方案
為了繼續(xù)前進(jìn),讓我們回顧一下以下顯示系統(tǒng)架構(gòu)的圖表。

我們有一個 JavaScript 客戶端應(yīng)用程序、一個負(fù)責(zé)用戶授權(quán)的身份驗(yàn)證應(yīng)用程序和一個具有主要應(yīng)用程序功能的 Erlang 應(yīng)用程序。流程如下:
客戶端使用憑證向 Auth Application 發(fā)出 HTTP 請求;
Auth Application 檢查 creds,生成 token 并通過 HTTP 請求發(fā)送到 Erlang Cluster;
Erlang 應(yīng)用程序確認(rèn)收到令牌并向 Auth 應(yīng)用程序發(fā)送帶有確認(rèn)的 HTTP 響應(yīng);
Auth App 向客戶端應(yīng)用程序發(fā)送 HTTP 響應(yīng)。此響應(yīng)包括生成的令牌;
客戶端使用令牌通過我們的 HAProxy 負(fù)載均衡器與 Erlang 應(yīng)用程序建立 websocket 連接。
這是我們的基本流程,稍作修改。我們在 Erlang 應(yīng)用程序中添加了一個簡單的模塊,用于跟蹤每個 Erlang 節(jié)點(diǎn)上的 websocket 連接數(shù)量。由于 Erlang 的 “分布式” 特性,每個節(jié)點(diǎn)都知道其他節(jié)點(diǎn)的連接。
所以我們可以選擇一個連接較少的節(jié)點(diǎn)。我們獲取此節(jié)點(diǎn)的公網(wǎng) IP 地址,然后發(fā)送回 auth 應(yīng)用程序。然后,身份驗(yàn)證應(yīng)用程序?qū)⒋?IP 與令牌一起發(fā)送回客戶端??蛻舳耸褂檬盏降?IP 地址和令牌建立 WS 連接。所以最終的圖表是這樣的:

現(xiàn)在我們可以:
擺脫 WS 負(fù)載均衡器,這使我們的系統(tǒng)不那么復(fù)雜;
添加 Erlang 節(jié)點(diǎn),而無需重新配置系統(tǒng)的其他部分。
另外:
WS 連接現(xiàn)在在 Erlang 節(jié)點(diǎn)之間均勻分布;
該系統(tǒng)可輕松水平擴(kuò)展;
我們不必對 Erlang 節(jié)點(diǎn)使用彈性 IP。
綜上所述,WebSocket負(fù)載均衡是一項(xiàng)復(fù)雜但重要的技術(shù),它能夠提高系統(tǒng)的可用性、可擴(kuò)展性和性能。在設(shè)計(jì)和實(shí)現(xiàn)WebSocket負(fù)載均衡方案時,需要充分考慮WebSocket的特殊需求,并選擇合適的負(fù)載均衡器和策略進(jìn)行配置和優(yōu)化。
