Ⅰ 聊聊 分布式 WebSocket 集群解決方案
WebSocketSession與HttpSession的對比
在Spring集成的WebSocket中,每個WebSocket連接都有一個對應的會話:WebSocketSession。在建立連接後,通過WebSocketSession進行與客戶端的通信。然而,WebSocketSession無法序列化到Redis,因此在集群中無法實現會話共享。相反,HttpSession的Redis共享解決方案已存在。
嘗試將關鍵信息緩存到Redis並重構WebSocket會話的方法並不可行。現在,讓我們看看WebSocket會話與Http會話之間的區別。總的來說,Http會話共享有解決方案,且簡單,通過引入spring-session-data-redis和spring-boot-starter-redis依賴即可實現。
Netty與Spring WebSocket的對比
最初,使用Netty實現WebSocket服務端搭建。Netty使用NIO模型,提供極高的並發量。然而,單獨使用Netty可能會遇到一些問題。相比之下,Spring WebSocket被Spring Boot很好地集成,使用起來非常方便。實現WebSocket服務只需簡單幾步:添加依賴、配置類和實現消息監聽類。為了更好地與Spring Cloud家族兼容,最終採用了Spring WebSocket。
應用服務架構與WebSocket集群解決方案
應用既負責RESTful服務,也負責WebSocket服務。未將WebSocket服務模塊拆分是為了簡化服務間調用。要實現WebSocket集群,從Zuul轉型至Spring Cloud Gateway是必要的。Zuul 1.0不支持WebSocket轉發,Zuul 2.0開始支持WebSocket,並且開源了。為了實現SSL認證和動態路由負載均衡,需要在YAML文件中配置某些項。還需配置一個filter以避免HTTP請求錯誤。至此,基本框架搭建完畢。
WebSocket集群通訊解決方案
最簡單的解決方案是session廣播,適用於並發需求不高的情況。此方法易於實現,但存在計算力浪費問題。為了解決此問題,可以使用一致性哈希演算法。
一致性哈希演算法應用到WebSocket集群,需要解決服務UP/DOWN問題。當伺服器DOWN時,會自動關閉連接,影響哈希環映射。更新哈希環,避免轉發至DOWN狀態的伺服器。當服務UP時,需要重新配置哈希環,或斷開特定session連接。哈希環的實現細節較為復雜,需要根據實際情況設計演算法。
網關如何根據WebSocket請求轉發至指定伺服器?
通過負載均衡實現。Spring Cloud Gateway或Zuul默認集成了Ribbon,需要根據客戶端發來的UserID重寫Ribbon負載均衡演算法。將請求轉發至哈希環上找到的IP地址。最後,用戶溝通時,通過ID進行哈希計算,獲取對應伺服器上的會話。
Spring Cloud Finchley.RELEASE版本中Ribbon的不完善之處
在實際操作中發現Ribbon存在兩個不完善之處。雖然暫時無法在Ribbon上實現一致性哈希演算法,但可以通過客戶端發起兩次請求(一次HTTP,一次WebSocket)來間接實現。期待Ribbon更新以提供更優雅的WebSocket集群解決方案。