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

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

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