如何设计一个IM系统?


一、什么是IM系统?

IM系统是即时通讯(Instant Messaging)系统的简称。
它是一种实时、私密、便捷的在线通讯方式。用户可以通过文字、图片、音频、视频等多种方式进行信息交换。
常见的即时通讯工具有微信、QQ等。

常见的IM术语:

  • 用户:系统使用者
  • 消息:用户之间沟通的内容,可以是文本、语音、图片、表情、文件等内容
  • 会话:两个人之间的聊天
  • 群聊:多个人(通常是两个人及以上)之间的聊天
  • 终端:用户使用IM的机器,如Android端、iOS端、PC端
  • 未读数:用户还没读的消息数
  • 置顶:将与某个人的会话放在会话列表的最顶上(方便查看)
  • 用户状态:如在线、离线、忙碌等
  • 关系链:用户与用户之间的关系,如关注、好友、拉黑等
  • 信箱:即Timeline,一个收发消息的队列(如一个会话就可以算是一个信箱)

二、消息如何发送给别人呢?

消息从发出到别人收到,看起来很简单,但是如果设计方案不合适的话,可能会有各种各样的问题。

消息的发送一般有两种扩散方式:

  • 读扩散:用户与其他每个用户都有一个独立的信箱,读消息的时候从每一个信箱里取
  • 写扩散:每个用户都有自己的信箱,存放别人发给自己的消息

当然,这两种消息扩散方式没有谁好谁不好,他们分别都有一些优点和缺点:

  • 读扩散:优点是写操作方便,同时搜索两个人之间的聊天记录很方便。缺点是读操作很重,会话列表需要从每一个信箱里读消息
  • 写扩散:优点是读操作方便,方便做多终端数据同步。缺点是写操作很重,比如有一个万人大群,发一条消息就要同步9999个信箱

三、如何设计消息ID?

想一下,如果我们随便生成一个ID就用来做消息ID会有什么问题吗?

  • 可能会生成重复的消息ID
  • ID无序可能会导致消息排序性能差
  • 没有规则的ID可能无法判断是否有丢消息的问题(两个随机的ID中间我们无法判断是否还有其他ID存在但丢失了的)

分析一下我们要考虑的重点是:

  • 有序性
  • 不可重复性

所以分布式ID是一个好的选择,具体可参考文章《如何设计分布式ID?

四、如何做新消息获取?

消息发送后要如何到达对方的消息列表里呢?我们一般会有一下几种方式:

  • 推模式:服务端有新消息主动推送给客户端(实时性高)
  • 拉模式:客户端主动拉取最新消息(实时性低)
  • 推拉结合模式:服务端有新消息主动通知客户端来拉

一般的IM系统都会采用推模式来做,因为实时性是IM系统最重要的一个特性之一。但是推模式也不能保证推的数据不会丢,如果网络异常、用户在线状态异常,是有可能出现消息丢失的。所以,在推模式的基础上,我们可以加上定时拉的方式来保证数据最终一致性。

总结:用推拉结合模式可以很好解决消息丢失的问题,而推拉结合模式最好用写扩散,因为只需要拉一条Timeline即可,而读扩散需要拉n条Timeline,定时拉的时候性能很差。

五、IM系统的技术痛点

// TODO


文章作者: GaryLee
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 GaryLee !
  目录