SpringBoot系列21SpringWebsocket实现websocket集群⽅案讨论
diy
概述
本⽂对websocket集群的⽅案进⾏讨论:
1. 在websocket集群中,后端准确将指定的消息推送到指定的⽤户,前端实时接收服务推送的消息
2. 对websocket集群的⽅案进⾏讨论,并确定最佳⽅案
webscoket集群⽅案
15万韩币集群⽅案分析
在上个博⽂中实现向指定⽤户发送消息的功能,但是我们将提供websocket服务的服务进⾏集群(如上图)则存在如下问题:
上图中,⽤户A通过websocket注册到服务A,服务A通过STOMP协议订阅RabbitMQ上的消息,同理⽤户B。如果⽤户A连接到服务A 上,那么在位于服务B上的MQ模块即使使⽤SimpMessagingTemplate实例向⽤户A发送消息,此消息也⽆法到达⽤户A,原因是因为服务B上没有服务A的注册信息,⽆法准确的推送消息.只有在服务A上的MQ模块使⽤SimpMessagingTemplate实例向这个⽤户发送消息,消息才会到达⽤户A
针对这个问题下⽂我们通过3个⽅案解决这个问题,并详细分析每个⽅案的有缺点。
webSocket集群⽅案⼀
陌上寸草
概述
不管消息的接收者连接在哪个服务上,每个服务A/B都接收消息,对相同的消息都使⽤SimpMessagingTemplate实例进⾏推送,保证总有⼀个消息会被⽤户收到。
一直造句
详细流程如下:
1. ⽤户A/B分别通过ws连接服务A/B, 然后服务A/B通过stomp协议接⼊RabbitMQ
2. 消息发送者将消息发送到RabbitMQ的交换机上,使⽤扇形交换机。这样保证同⼀个消息可以同时被服务A/B接收
3. 两个服务上的MQ模块接收对应消息后,不管对应的⽤户是否是通过⾃⼰连接到RabbitMQ,直接使
⽤SimpMessagingTemplate实例向消息中指定的⽤户推送消息
4. ⽤户A/B接收到对应的消息
优点:
1. 实现⽐较简单
湖南工学院分数线
不⾜:
1. 消息⽣产者发送消息的RabbitMQ交换机必须是⼴播功能,如扇形交换机
2. 为了保证消息顺利到达⽤户,相同的消息必须在两个服务A/B上执⾏相同的操作。这样如果服务越多,则重复的发送消息越多
3. 如果⽤户不在线,⽆论发送多少消息⽤户都不能收到
webSocket集群⽅案⼆
概述
使⽤redis缓存⽤户的websocket连接信息,记录⽤户登录到哪个服务上,当有消息过来时,将消息推送到⽤户登录的服务,然后服务都使⽤SimpMessagingTemplate实例进⾏推送
在⽅案⼀的基础上增加如下功能:
1. 服务A/B上增加MQ模块,服务A/B上MQ模块会连接到RabbitMQ,分别订阅队列A/B
2. 服务A/B增加WS模块,当websocket连接过来时,将此⽤户的连接信息存储到redis上,系统记住每个⽤户登录的到哪个服务
3. 消息⽣产者将消息推送到交换机,不直接推送到服务A/B
4. 增加新的模块dispatch,此模块接收到消息,然后从redis中读取要消息要推送到⽤户连接到那个服务器上,然后将消息发送到⽤户连接服务对应的队列中。如果消息要发送给⽤户B,则dispatch模块会将消息发送到队列B
5. 服务A/B的MQ模块接收到消息后,使⽤SimpMessagingTemplate实例向指定⽤户推送消息
元宵佳节的诗句优点:褶皱纸
1. 此⽅案克服上⼀个⽅案不⾜的地⽅
缺点
1. 实现复杂
2. 发送MQ消息的次数增加1倍
webSocket集群⽅案三
概述
不使⽤SimpMessagingTemplate,使⽤RabbitMQ的客户端API直接向⽤户在RabbitMQ上订阅的队列发送消息
发现⽤户通过浏览器登录websocket并注册RabbitMQ时,此时这个连接会在RabbitMQ建⽴⼀个队列,队列的名称类似stomp-subscription-*,此队列绑定到默认交换机pic,路由键为”web订阅队列名称+’-ur’+websocket ssionId”(这⾥是demo-urpjplggbl,demo是stomp weboscket连接的队列名称,pjplggbl登录websocket登录时的websocket ssionId值),图⽚如下:
根据这个,设计如下架构:
在⽅案⼀的基础进⾏如下修改,新的架构图流程如下:
1. 服务A增加WS模块,当websocket连接过来时,将此⽤户的连接信息(主要是websocket sionId值)存储redis中
必修二物理
2. 消息⽣产者发送消息到的交换机,这些服务不直接推送服务A/B
3. 增加新的模块dispatch,此模块接收推送过来的信息,并从redis中读取消息接收⽤户对应的websocket sionId值,然后根据上⾯的规则计算出⽤户对应的路由键,然后将消息发送到⽤户订阅的队列上
4. 前端接收消息
优点:
1. 即克服第⼀个⽅案不⾜的地⽅,⼜⽐第⼆个⽅案简单
结论
⽅案三是最好的⽅案,下⼀篇⽂章,我们会介绍如何在代码中实现⽅案三