基於spring-boot、spring-cloud的websocket服務器多點負載均衡改造


背景

為應對更多用戶使用socket的場景,准備對存放websocket的服務器進行多點搭建並配置負載均衡。

 

問題

服務器上了多點負載均衡以后,基於socket的部分功能發生了有規律的失效,查看后台日志發現了原因。

基於socket的功能使用的session存放在其他負載均衡的服務器上,所以在當前服務器無法實現相應操作。

舉個實例,有兩台加了負載的socket服務器分別為A、B。服務器A擁有用戶1的socket連接即session句柄,服務器B擁有用戶2的session句柄,

此時client端發送給用戶1一條消息,消息內容是“kill程序員祭天消息”,由於socket服務器的負載均衡策略,該消息可能被發送到A或B服務器。

當A服務器接收到該請求時,A服務器可以完成給用戶1發送消息的任務,因為A服務器擁有可以給用戶1發送消息的句柄。但是服務器B接收到此消息的時候,B嘗試着尋找用戶1的句柄但是在列表當中沒有找到該句柄,所以無法將消息發送出去,此時消息丟失了。換言服務器只能與當前建立連接的用戶進行通信。

 

解決方案的嘗試

不可行的方案

redis集中管理連接,這種方式是最開始想到的一種方式,這種方法的好處在於redis集中管理用戶連接。該方法預期將用戶的連接信息存放在redis服務器,當服務器接收到發送消息請求時,去redis獲取與用戶的連接,然后發送消息。

然而這種方法夭折了~~,問題在於session管理着與用戶的長連接,該數據無法存入redis。筆者嘗試着將session以HashMap、Object形式存入redis,此時redis報錯。另外嘗試將session以Json形式存入redis,但是在session轉為Json的時候發現session是不能被序列化的,自然不能轉為JSON格式了。

可行的方案

使用kafka廣播形式,將消息廣播到各服務器。首先將client端的請求吐入kafka,並且配置各接收服務器使用廣播方式接收,即使用不同群組接收同一個topic,這樣每個服務器都能接收到該請求,但是只有一個服務器可以將消息發出。該方法存在缺點但確實解決了此問題。該方法缺點在於,雖然保證的socket的負載均衡,但是服務器down掉以后,該服務器與用戶的長連接就消失了。

 

哪路神仙有更好的方案,歡迎在評論區回復~~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM