思考(五十):IM 服务器实现(一)

可能的方案

IM 服务器能想到的有以下几种实现方式:

  • 直接消息转发类型
  • 消息队列型
  • P2P 点对点型

下面从全服消息入手,依次分析下 3 种类型的优劣

直接消息转发类型

时序图如下:

Client Client(All) Gateway Gateway(All) Chat 发送一条`全服消息` 转发该消息给某 Logic 给所有 Gateway 转发该消息 给所有的 Client 转发该消息 Client Client(All) Gateway Gateway(All) Chat

时序图分析:

  • 代码实现简单
  • 假设同时在线 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

client sdk comet logic kafka 发送一条`全服消息` 转发该消息给某 logic 把该消息发布到 kafka kafka 的风骚操作(略) client sdk comet logic kafka

时序图2

job kafka comet(All) client sdk(All) job 订阅到该条`全服消息` 给所有 comet 转发该消息 给所有 client sdk(All) 转发该消息 job kafka comet(All) client sdk(All)

时序图分析:

  • 代码实现稍微复杂, Chat 功能被拆成 3 块,并引入消息队列的概念
  • 方案 1 的两个假设也存在
    • 假设同时在线 N 个人,1 条全服消息进入服务器到出来,被放大了 N 倍
    • 假设同时在线 N 个人,1 秒内 N 个人都发送了全服消息,则 1 秒内 N 条全服消息,被放大了 N2

但是这 2 个假设,被架构与 kafka 给稀释掉了:

  • 聊天峰值期,会导致 Job 来不及取走socket 系统接收缓冲区数据,导致 Job 卡住,无法继续提供服务
  • Job 出现假死现象, kafka 能正确处理这种情况,并会做消息缓冲(如存到硬盘上等等)
  • 通过 Chat 功能的拆分,架构上优势,使得聊天峰值期仅 job 节点存在的状态,并通过 kafka 自动调节、缓冲峰值期带来的压力

结论:

  • 该方案能应对突发情况
  • 但是,突发情况下,聊天功能体验大概率出现无法很好的聊天
  • 发送的消息,可能很久才会收到

以上

(篇幅、时间问题, P2P 点对点类型,待下文分解)

发布了129 篇原创文章 · 获赞 73 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/u013272009/article/details/88802930