【自研项目之分布式IM】07. 核心篇-消息的存储实现

346 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情

IM消息的存储的经典方案有两种:读扩散与写扩散。

1. 读扩散

消息只存储一份,所有成员都去读取同一条消息。

  • 缺点:
    • 需要额外存储信息,比如群ID,会话ID等标识是某个群或好友的消息。
    • 接收端获取消息业务复杂,比如新用户进群、群成员删除消息、获取所有群消息等。
  • 优点
    • 存储空间小。
    • 写操作压力小,每条消息只需要写入一次。

2. 写扩散

每个用户都有一个接收消息的信箱,即发送一条群聊每个群成员都会保存一份。

  • 缺点:
    • 存储空间变大。
    • 并发写操作。比如万人群,每条消息并发写入1w次。
  • 优点
    • 查询消息压力分散,读取速度快
    • 接收端消息处理简单,只需要从个人信箱中读取消息。
    • 对于已读、未读、总未读数等这些复杂逻辑可以很好的处理。

读写扩散.png

3. 单聊消息的存储方案

单聊消息的存储推荐写扩散,这样双方处理删除消息、撤回、新消息拉取都很方便。不过这里写扩散可以做个优化,消息只需要保存一份,双方用户只需要存储该条消息的索引来节省存储空间。

4. 群聊消息的存储方案

群聊消息的存储就比较复杂,加上烦人的企业IM的已读、未读、n人读等等。下面我们来分析下选用哪种方案合适。
我们知道一个聊天的IM肯定是读多写少的,如果选用了读扩散,那整个系统的读操作是很巨大的。下面看下读扩散处理群聊的场景:

  • 比如你加了100个群,每次都需要都依次检索这100个群的消息。而写扩散用空间换时间,接收端只需要从一个信箱中获取即可。对比可知两种方式拉取一次群消息的读取量是100:1。
  • 某用户删除群消息需要额外记录删除的消息,那么该用户拉取群消息的时候需要关联删除消息表做合并数据。
  • 新用户进群旧消息不可见,那么需要记录该用户进群时的时间戳或进群时最新一条的msgId等额外信息实现。
  • 对于已读、未读等复杂逻辑处理起来很复杂。

因此写扩散更合适作为群聊消息的存储方案。对于以上的场景,写扩散也很好的支持。

对于大群(万人群或更大)用写扩散来说,每条新消息的写入并发又会非常巨大,这时候读扩散更适合。其实这就需要在产品设计上解决了,比如微信设置了群上限。读写扩散存储是可以穿插使用的,不限定死只能用一种。