談談websocket集群的解決方式


  上文我們已經利用websocket實現微信二維碼支付的業務。

  上述實現在單機環境中實現是沒有什么問題的,無非就是客戶端連接服務端,首先將連接的websocketsession存在一個map里面,當異步響應的時候,

根據流水號獲取map里面對於的websocketSession,給指定的客戶端發送消息。

       但實際生產環境中,服務器一般是采用集群模式,首先,比方支付來說,接收第三方響應的服務器可能是有多台,然后具體是根據nginx隨機路由轉發,

假設異步響應的服務器有2台,A和B,而且連接websocket的代碼是寫在響應工程里面的,這時p1客戶端去連接websocket的時候,通過域名實現websocket協議

,具體可在nginx里面配置,是隨機轉發到某一台,假設連接到A,這時session信息保存在A服務器,假設用戶支付完成后,第三方異步通知也是隨機轉發A和B,

如果運氣好,轉發到A,此時異步響應能拿到session值,則能成功通知到客戶端。如果不巧,轉發到了B,則異步通知邏輯是執行了,但發現客戶端一直沒有收到

消息,因為B服務器根本拿不到這個session值。

     解決上面的問題,首先考慮websocket是否可以在兩台機器上共享,實現數據共享,當時想到的是是否可以將websocketsession序列化后存儲到redis里面,然后

從redis里面獲取給用戶發送通知,最終發現不可行,因為websocketsession沒有實現序列化接口,不能存在redis里面,另外就算能存儲,客戶端連接的是A,B就算拿到

session,但不能保證推送過去能成功,所以想到是否可以將上次連接的服務端記錄下來,只要連接A,我就讓A去發送,連接B,我就讓B發送,既然不能將session存到redis

里,我可以考慮將流水號連接的服務端的ip存到redis里面,然后將發送消息的代碼轉移到一個controller,在異步通知的地方本來是直接執行發送消息的業務代碼,改成調用

Http請求同時傳遞一個參數,根據這個參數可由流水號獲取之前連接的服務器的ip,然后配置nginx解析參數指定轉發到那一台。

     通過上面的程序問題其實已經解決,其實如果從架構上優化的話,可以將websocket工程單獨拆分成一個工程,不和異步通知的代碼整在一起,由於異步通知的代碼需要在

外網部署多套,而websocket可以只部署一套,這樣nginx也不需要做指定參數轉發的處理,比上述的方案更加優化。

    然而實際中,如果websocket真的集群了,那么這個問題依然還是會出現,當然依靠redis和nginx指定參數轉發,還是能做到點對點,只要所有websocket工程都不會宕機,

上述實現方案其實並沒有實現websocketsession的共享,假設p1連接到A,異步的時候A宕機,這時p1就收不到消息,實際中集群按理說B還是可以給p1發送成功的消息,這就

可以利用消息隊列的訂閱發布的功能來模擬發送這個消息。


免責聲明!

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



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