内容简介:在上个博文上图中,用户A通过websocket注册到服务A,服务A通过STOMP协议订阅RabbitMQ上的消息,同理用户B。如果用户A连接到服务A上,那么在位于服务B上的MQ模块即使使用SimpMessagingTemplate实例向用户A发送消息,此消息也无法到达用户A,原因是因为服务B上没有服务A的注册信息,无法准确的推送消息.只有在服务A上的MQ模块使用SimpMessagingTemplate实例向这个用户发送消息,消息才会到达用户A针对这个问题下文我们通过3个方案解决这个问题,并详细分析每个方
在上个博文 Spring Boot系列20 Spring Websocket实现向指定的用户发送消息 中实现向指定用户发送消息的功能,但是我们将提供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实例进行推送,保证总有一个消息会被用户收到。
详细流程如下:
- 用户A/B分别通过ws连接服务A/B, 然后服务A/B通过stomp协议接入RabbitMQ
- 消息发送者将消息发送到RabbitMQ的交换机上,使用扇形交换机。这样保证同一个消息可以同时被服务A/B接收
- 两个服务上的MQ模块接收对应消息后,不管对应的用户是否是通过自己连接到RabbitMQ,直接使用SimpMessagingTemplate实例向消息中指定的用户推送消息
- 用户A/B接收到对应的消息
优点:
- 实现比较简单
不足:
- 消息生产者发送消息的RabbitMQ交换机必须是广播功能,如扇形交换机
- 为了保证消息顺利到达用户,相同的消息必须在两个服务A/B上执行相同的操作。这样如果服务越多,则重复的发送消息越多
- 如果用户不在线,无论发送多少消息用户都不能收到
webSocket集群方案二
概述使用 redis 缓存用户的websocket连接信息,记录用户登录到哪个服务上,当有消息过来时,将消息推送到用户登录的服务,然后服务都使用SimpMessagingTemplate实例进行推送
在方案一的基础上增加如下功能:
- 服务A/B上增加MQ模块,服务A/B上MQ模块会连接到RabbitMQ,分别订阅队列A/B
- 服务A/B增加WS模块,当websocket连接过来时,将此用户的连接信息存储到redis上,系统记住每个用户登录的到哪个服务
- 消息生产者将消息推送到交换机,不直接推送到服务A/B
- 增加新的模块dispatch,此模块接收到消息,然后从redis中读取要消息要推送到用户连接到那个服务器上,然后将消息发送到用户连接服务对应的队列中。如果消息要发送给用户B,则dispatch模块会将消息发送到队列B
- 服务A/B的MQ模块接收到消息后,使用SimpMessagingTemplate实例向指定用户推送消息
优点:
- 此方案克服上一个方案不足的地方
缺点
- 实现复杂
- 发送MQ消息的次数增加1倍
webSocket集群方案三
概述不使用SimpMessagingTemplate,使用RabbitMQ的客户端API直接向用户在RabbitMQ上订阅的队列发送消息
发现用户通过浏览器登录websocket并注册RabbitMQ时,此时这个连接会在RabbitMQ建立一个队列,队列的名称类似stomp-subscription-***,此队列绑定到默认交换机amq.topic,路由键为"web订阅队列名称+'-user'+websocket sessionId"(这里是demo-userpjplggbl,demo是stomp weboscket连接的队列名称,pjplggbl登录websocket登录时的websocket sessionId值),图片如下:
根据这个,设计如下架构:
在方案一的基础进行如下修改,新的架构图流程如下:
- 服务A增加WS模块,当websocket连接过来时,将此用户的连接信息(主要是websocket sesionId值)存储redis中
- 消息生产者发送消息到的交换机,这些服务不直接推送服务A/B
- 增加新的模块dispatch,此模块接收推送过来的信息,并从redis中读取消息接收用户对应的websocket sesionId值,然后根据上面的规则计算出用户对应的路由键,然后将消息发送到用户订阅的队列上
- 前端接收消息
优点:
- 即克服第一个方案不足的地方,又比第二个方案简单
结论
方案三是最好的方案,下一篇文章,我们会介绍如何在代码中实现方案三
以上所述就是小编给大家介绍的《Spring Boot系列21 Spring Websocket实现websocket集群方案讨论》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Redis集群实现原理探讨
- Dubbo(五):集群容错的实现
- SpringSession+Redis实现集群会话共享
- 快速实现 Tomcat 集群 Session 共享
- 基于 ZooKeeper 实现爬虫集群的监控
- 如何使用 Prometheus 轻松实现集群监控?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Hacking Growth
Sean Ellis、Morgan Brown / Crown Business / 2017-4-25 / USD 29.00
The definitive playbook by the pioneers of Growth Hacking, one of the hottest business methodologies in Silicon Valley and beyond. It seems hard to believe today, but there was a time when Airbnb w......一起来看看 《Hacking Growth》 这本书的介绍吧!