本文已参与「新人创作礼」活动,一起开启掘金创作之路。
背景
单体应用下只有一台服务器,所有的客户端连接的都是这一台消息服务器,所以当发布消息者发送消息时,所有的客户端其实已经全部与这台服务器建立了连接,直接群发消息就可以了。
但是如果是使用负载均衡,集群环境下,假如我们有两台消息服务器A和B,那么客户端通过Nginx负载均衡后,就会有一部分连接到A服务器,另一部分连接到B服务器,发布消息者发送消息时,有可能在A服务器上发消息,但是此时,用户连接信息却是存在B服务器上面,这样就无法发送成功。
现在我们知道了根本原因是生产消息时,只有一台消息服务器能够感知到,所以我们只要让另一台消息服务器也能感知到就可以了,这样感知到之后,它就可以群发消息给连接到它上边的客户端了。
解决分布式下的Websocket问题
可以使用Redis的发布订阅模式,也可以使用RabbitMQ消息中间件来实现。
这2种方式各有好坏,使用Redis的方式可以少引入一个组件,减少系统复杂性,开发更方便,但是也有缺点,消息无法持久化,redis挂了,消息就都没了。
使用RabbitMQ消息可以持久化,也更加专业,但是多引入了一个组件,增加了系统的复杂性。
具体使用哪个组件,需要看此消息是否允许突发情况丢失消息,如果可以容忍,Redis不失为一个好选择,否则就老实的使用RabbitMQ来实现。
大概原理
我们主要是引入了中间件,通过发布订阅模式,让每个消息服务器启动的时候都去订阅消息,而无论哪台消息服务器在发送消息的时候都会发送给中间件,这样每台消息服务器就都会感知到发送消息的事件,从而再通过Websocket发送给客户端。