最近在做一个 IM 的开发,初次尝试 IM 开发,碰到点问题向懂这块的兄弟们请教一下。直接上图: 先简单说一下技术方案吧:
用户登录之后与一台 server 建立连接,会话信息保存到本地( SessionMap ),就是把 userId 和 channel 的映射关系存起来,再把 userId 和 server 所在主机 MAC 地址的映射关系存到 redis 中。
每台 server 在启动的时候,会在 MQ 里订阅自己所在主机的 MAC 主题(这里是把主机 MAC 作为 MQ 的 Topic 用的)。
两个 user 之间相互发消息:
如果两个 user 在同一台主机,直接从本地 SessionMap 获取对方 channel 完成消息传递;
如果两个 user 在不同的主机,一个 user 发完消息后,server 端从 redis 中获取对方所在主机 MAC (假设为 MAC_2 ),然后把消息丢到 MQ 的 MAC_2 Topic 中,传递到对方主机,再从对方主机 SessionMap 中取出对方 channel ,完成消息传递;
如果是传给 MAC_3 上的 user ,user 不在线,就离线存储。
现在问题是,假如说某台机器故障了,比如假设 MAC_3 故障,硬件损坏,那 MQ 中 MAC_3 Topic 中的消息会越积越多,而这个 Topic 又没有订阅者,那这部分信息该怎么处理?
1
Nazz 2023-02-17 20:01:11 +08:00 via Android
做好容灾就行了
|
2
billlee 2023-02-17 20:03:24 +08:00 via Android
应该用 userId 的 hash 来分区。哪有人用服务器的地址分区的。
|
3
wyx119911 2023-02-17 20:14:14 +08:00
这架构很难维护,服务应该做成无状态的
|
5
KristenGe 2023-02-17 22:26:14 +08:00
@billlee 能具体点吗?目前 MQ 中的消息等于是通过 userId 寻址,找 Topic 送达对应主机,userId 分区是怎么个做法?
|
8
KristenGe 2023-02-17 23:16:38 +08:00
@Nazz 这个其实没有问题的,无非就是 client 和 server 之间做一层 routing ,现在问题是不同节点上的用户之间消息交互,是通过对方机器标识(或服务标识)做 MQ 的 Topic ,精准送达,如果服务 down 了,topic 成无订阅状态,消息无法消费了。现在能想到的是用 ZK ,不过前期不想太复杂。
|
9
javapythongo 2023-02-17 23:41:04 +08:00
可以把用户是否在线存储到 redis 中,发送消息前,判断下,不在线就直接离线存储
|
10
b1ghawk 2023-02-17 23:41:06 +08:00 via Android
可以把消息泛播到每个服务器上,
每个服务器判定这条消息的用户是否在本机上又连接,有的话就发出去。 |
11
huanw 2023-02-17 23:51:11 +08:00
楼上的老哥说得对,消息应该散播到集群每个节点上,因为你每个节点都有 SessionMap ,由节点来决定怎么给客户端发消息。做到无状态才有利于扩展,比如断线重连,本来连接节点 1 ,断线后连接节点 2 ,这都不影响消息发送。
|
12
mawerss1 2023-02-18 00:02:07 +08:00 via Android
不说这个系统设计如何,单论这个问题,在你这个设计里挂了消息就只能扔掉,如果丢消息,你需要在发送端做好存储
|
13
KristenGe 2023-02-18 01:40:34 +08:00 via Android
@b1ghawk 这种做法我感觉在 IM 的系统中不太现实,量一旦上来了,会造成网络堵塞;而且每台机器都等于要处理全网的消息量,性能一定会成为瓶颈
|
15
Nazz 2023-02-18 07:29:15 +08:00 via Android
@gemingsy 服务挂了让副本起来工作啊,每个编号的 Deployment 搞多个 Pod ,订阅同一个主题
|
17
PythonYXY 2023-02-18 11:08:55 +08:00
路由信息单独保存在 redis 或者 kv 数据库中,抽象出一个路由服务集群统一消费 MQ 消息,对消息进行路由推送。不过要考虑路由服务的消费能力,避免过高的消息延迟。
|
18
NUT 2023-02-18 11:23:57 +08:00
通用问题。 其实必须有一个主去做 session 状态的分配。 陌陌老早时候有一个 ppt 分享他们的策略。 分三层,一层是接入层, 无状态,可以任意扩展,主要是接受链接, 第二层 逻辑层,保证消息业务逻辑的路由等, 第三层存储。
其实你的服务没有脑子,需要有一个脑子,去做这种订阅关系的维护, 也就是 接入层上线以后, 由 master 去做分配 session 相关策略。主要保证 master 强一致就行。 不过咋说,难度就会上一个层级。 还可以看看 codis 还有 tidb 等分布式设计。 会有帮助的。 |
19
guonaihong 2023-02-18 17:14:12 +08:00
收藏下下。。。
|