技术分析
我们在开发时会遇到需要使用即时通讯的场景,当然,实现方式很多,Socket
、MQTT
、Netty
....等等。
具体用哪种就在于业务的需求了,去选择合理的方式实现。
今天小简要聊的场景便是分布式环境下,WebSocket
的消息共享问题。
分布式环境下,业务方面往往最需要解决的是数据同步共享这类问题。
此时出现了一个场景,后端存在一个分布式服务,我需要两个服务都能收到WebSocket
的消息,如何去实现?
或者说,服务端项目存在多个负载均衡实例,实例均在不同的实例上,这样当一次请求负载到A服务器实例时,socket
的session
在A服务器线程上,第二次请求负载到另一台B服务器的实例,此时B服务器并不存在A服务器的Session
(即Socket
的会话消息)。
思考解决
思路一(失败)
我们首先思考,改如何解决这个问题呢?要实现同步,根据上面的需求,我们可以直接定位到Socket的Session不能共享问题,只要可以共享会话对象,那就可以解决当前问题。
没错,小简也是这样想的,但是,实际上是错误的,请看下文。
我们首先联想到,分布式下,我们的分布式锁、分布式状态信息,都是可以通过Redis
去实现一个共享的,那我们直接给Socket
的Session
通过Redis
共享不就可以。
思路确实是对的,但是使用
Redis
共享对象是有条件的,要去实现Serializable
接口,才可以被序列化。
我们查看源码就会发现,Socket
的Session
是不能被序列化的,那自然不能去使用Redis
来实现Session
对象的共享了。
为什么HttpSession
可以使用Redis
共享?
/** * @author JanYork * @date 2023/3/14 11:36 */ org.apache.catalina.session.StandardManager org.apache.catalina.session.PersistentManager
WEB
的中的HttpSession
主要是通过上面的两个管理器实现序列化的。
StandardManager
是Tomcat
默认使用的,在web
应用程序关闭时,对内存中的所有HttpSession
对象进行持久化,把他们保存到文件系统中。
默认的存储文件为:<tomcat安装目录>/work/Catalina/<主机名>/<应用程序名>/sessions.ser
PersistentManager
比StandardManager
更为灵活,只要某个设备提供了实现org.apache.catalina.Store
接口的驱动类,PersistentManager
就可以将HttpSession
对象保存到该设备。
所以spring-session-redis
解决分布场景下的session
共享就是将session
序列化到redis
中,使用filter
加装饰器模式解决分布式场景httpsession
享问题。
注:此段参考自程序员DD大佬的文章。
思路二
既然不能共享对象,那我们共享消息不就可以,我们的目的是要其他实例也可以收到Socket
的消息,那我们就是个1
对n
的消息模型,一对多消息那就简单了。
哪些方法?
首先我们会第一时间想到,MQ
,也就是消息队列中间件。
其次我们也可以使用Redis
的发布订阅功能实现。
MQ
使用MQ
去实现一对多消息,相信也不需要我多说,MQ
天然的广播、发布订阅、点对点、路由这些消息模式可以很方便的解决这个问题。
Redis
Redis
实现有大佬已经写过了,请参考:
如何使用
Redis
解决WebSocket
分布式场景下的Session
共享问题: https://cloud.tencent.com/developer/article/1955783
尾述
说浅谈就浅谈,文章就这么短(暗暗窃喜:又水一篇,嘿嘿),下篇再见。