Websocket集群解决方案

最近在项目中在做一个消息推送的功能,比如客户下单之后通知给给对应的客户发送系统通知,这种消息推送需要使用到全双工的websocket推送消息 。

所谓的全双工表示客户端和服务端都能向对方发送消息 。不使用同样是全双工的http是因为http只能由客户端主动发起请求,服务接收后返回消息 。websocket建立起连接之后,客户端和服务端都能主动向对方发送消息 。
上一篇文章Spring Boot 整合单机websocket介绍了websocket在单机模式下进行消息的发送和接收:
Websocket集群解决方案

文章插图
用户A用户Bweb服务器建立连接之后,用户A发送一条消息到服务器 , 服务器再推送给用户B,在单机系统上所有的用户都和同一个服务器建立连接,所有的session都存储在同一个服务器中 。
单个服务器是无法支撑几万人同时连接同一个服务器,需要使用到分布式或者集群将请求连接负载均衡到到不同的服务下 。消息的发送方和接收方在同一个服务器,这就和单体服务器类似,能成功接收到消息:
Websocket集群解决方案

文章插图
但负载均衡使用轮询的算法,无法保证消息发送方和接收方处于同一个服务器,当发送方和接收方不是在同一个服务器时,接收方是无法接受到消息的:
Websocket集群解决方案

文章插图
websocket集群问题解决思路客户端和服务端每次建立连接时候,会创建有状态的会话session,服务器的保存维持连接的session 。客户端每次只能和集群服务器其中的一个服务器连接,后续也是和该服务器进行数据传输 。
要解决集群的问题,应该考虑session共享的问题,客户端成功连接服务器之后,其他服务器也知道客户端连接成功 。
方案一:session 共享(不可行)和websocket类似的http是如何解决集群问题的?解决方案之一就是共享session , 客户端登录服务端之后,将session信息存储在Redis数据库中,连接其他服务器时,从Redis获取session , 实际就是将session信息存储在Redis中,实现redis的共享 。
session可以被共享的前提是可以被序列化,而websocketsession是无法被序列化的,httpsession记录的是请求的数据,而websocketsession对应的是连接,连接到不同的服务器,session也不同 , 无法被序列化 。
方案二:ip hash(不可行)http不使用session共享,就可以使用Nginx负载均衡的ip hash算法,客户端每次都是请求同一个服务器,客户端的session都保存在服务器上,而后续请求都是请求该服务器,都能获取到session , 就不存在分布式session问题了 。
websocket相对http来说,可以由服务端主动推动消息给客户端,如果接收消息的服务端和发送消息消息的服务端不是同一个服务端,发送消息的服务端无法找到接收消息对应的session,即两个session不处于同一个服务端,也就无法推送消息 。如下图所示:
Websocket集群解决方案

文章插图
解决问题的方法是将所有消息的发送方和接收方都处于同一个服务器下,而消息发送方和接收方都是不确定的,显然是无法实现的 。
方案三:广播模式将消息的发送方和接收方都处于同一个服务器下才能发送消息,那么可以转换一下思路,可以将消息以消息广播的方式通知给所有的服务器,可以使用消息中间件发布订阅模式,消息脱离了服务器的限制,通过发送到中间件,再发送给订阅的服务器,类似广播一样,只要订阅了消息,都能接收到消息的通知:
Websocket集群解决方案

文章插图
发布者发布消息到消息中间件,消息中间件再将发送给所有订阅者:
Websocket集群解决方案

文章插图
广播模式的实现搭建单机 websocket参考以前写的websocket单机搭建 文章,先搭建单机

推荐阅读