可能的方案
IM 服务器能想到的有以下几种实现方式:
- 直接消息转发类型
- 消息队列型
- P2P 点对点型
下面从全服消息
入手,依次分析下 3 种类型的优劣
直接消息转发类型
时序图如下:
时序图分析:
- 代码实现简单
- 假设同时在线 N 个人,1 条
全服消息
进入服务器到出来,被放大了 N 倍 - 假设同时在线 N 个人,1 秒内 N 个人都发送了
全服消息
,则 1 秒内 N 条全服消息
,被放大了 N2 倍
上述分析中的 2 个假设,会导致如下问题:
- 聊天峰值期,会导致服务器来不及取走
socket 系统接收缓冲区
数据,导致 Gateway 、 Chat卡住
,无法继续提供服务 - 聊天峰值期,会导致服务器内存激增,Chat 可能会出现内存问题
结论:
- 该方案无法应对突发情况,大概率会出现 Gateway 、 Chat 假死现象
- 该方案无法应对突发情况,有概率会出现 Chat 内存溢出
消息队列型
下面分析下,github 上一个典型的消息队列型 IM 系统
github 地址: https://github.com/Terry-Mao/goim
先请上官方的架构图:
架构图说明:
goim 各服务功能 | 对应的直接消息转发类型 的各服务功能 |
---|---|
client sdk | Client 客户端 |
comet | Gateway |
job + logic + kafka | Chat |
其他服务 | 周边服务,非核心内容,请无视 |
可以看到, Chat 服务被拆成 3 个部分:job 、 logic 、 kafka
它们的交互时序图也被拆成了 2 个,如下:
时序图1
时序图2
时序图分析:
- 代码实现稍微复杂, Chat 功能被拆成 3 块,并引入消息队列的概念
- 方案 1 的两个假设也存在
- 假设同时在线 N 个人,1 条
全服消息
进入服务器到出来,被放大了 N 倍 - 假设同时在线 N 个人,1 秒内 N 个人都发送了
全服消息
,则 1 秒内 N 条全服消息
,被放大了 N2 倍
- 假设同时在线 N 个人,1 条
但是这 2 个假设,被架构与 kafka 给稀释掉了:
- 聊天峰值期,会导致 Job 来不及取走
socket 系统接收缓冲区
数据,导致 Job卡住
,无法继续提供服务 - Job 出现假死现象, kafka 能正确处理这种情况,并会做消息缓冲(如存到硬盘上等等)
- 通过 Chat 功能的拆分,架构上优势,使得聊天峰值期仅 job 节点存在
忙
的状态,并通过 kafka 自动调节、缓冲峰值期带来的压力
结论:
- 该方案能应对突发情况
- 但是,突发情况下,聊天功能体验大概率出现无法很好的聊天
- 发送的消息,可能很久才会收到
以上
(篇幅、时间问题, P2P 点对点类型,待下文分解)