IM核心概念
用户 :系统的使用者
消息 :是指用户之间的沟通内容。通常在IM系统中,消息会有以下几类:文本消息、表情消息、图片消息、视频消息、文件消息等等
会话 :通常指两个用户之间因聊天而建立起的关联
群 :通常指多个用户之间因聊天而建立起的关联
终端 :指用户使用IM系统的机器。通常有Android端、iOS端、Web端等等
未读数 :指用户还没读的消息数量
用户状态 :指用户当前是在线、离线还是挂起等状态
关系链 :是指用户与用户之间的关系,通常有单向的好友关系、双向的好友关系、关注关系等等。这里需要注意与会话的区别,用户只有在发起聊天时才产生会话,但关系并不需要聊天才能建立。对于关系链的存储,可以使用图数据库(Neo4j等等),可以很自然地表达现实世界中的关系,易于建模
单聊 :一对一聊天
群聊 :多人聊天
客服 :在电商领域,通常需要对用户提供售前咨询、售后咨询等服务。这时,就需要引入客服来处理用户的咨询
消息分流 :在电商领域,一个店铺通常会有多个客服,此时决定用户的咨询由哪个客服来处理就是消息分流。通常消息分流会根据一系列规则来确定消息会分流给哪个客服,例如客服是否在线(客服不在线的话需要重新分流给另一个客服)、该消息是售前咨询还是售后咨询、当前客服的繁忙程度等等
信箱 :本文的信箱我们指一个Timeline、一个收发消息的队列
读扩散 vs 写扩散
读扩散
我们先来看看读扩散。如上图所示,A与每个聊天的人跟群都有一个信箱(有些博文会叫Timeline),A在查看聊天信息的时候需要读取所有有新消息的信箱。这里的读扩散需要注意与Feeds系统的区别,在Feeds系统中,每个人都有一个写信箱,写只需要往自己的写信箱里写一次就好了,读需要从所有关注的人的写信箱里读。但IM系统里的读扩散通常是每两个相关联的人就有一个信箱,或者每个群一个信箱。
读扩散的优点:
- 写操作(发消息)很轻量,不管是单聊还是群聊,只需要往相应的信箱写一次就好了
- 每一个信箱天然就是两个人的聊天记录,可以方便查看聊天记录跟进行聊天记录的搜索
读扩散的缺点:
- 读操作(读消息)很重
写扩散
接下来看看写扩散。
在写扩散中,每个人都只从自己的信箱里读取消息,但写(发消息)的时候,对于单聊跟群聊处理如下:
- 单聊:往自己的信箱跟对方的信箱都写一份消息,同时,如果需要查看两个人的聊天历史记录的话还需要再写一份(当然,如果从个人信箱也能回溯出两个人的所有聊天记录,但这样效率会很低)。
- 群聊:需要往所有的群成员的信箱都写一份消息,同时,如果需要查看群的聊天历史记录的话还需要再写一份。可以看出,写扩散对于群聊来说大大地放大了写操作。
写扩散优点:
- 读操作很轻量
- 可以很方便地做消息的多终端同步
写扩散缺点:
- 写操作很重,尤其是对于群聊来说
注意,在Feeds系统中:
- 写扩散也叫:Push、Fan-out或者Write-fanout
- 读扩散也叫:Pull、Fan-in或者Read-fanout
唯一ID设计
通常情况下,ID的设计主要有以下几大类:
- UUID
- 基于Snowflake的ID生成方式
- 基于申请DB步长的生成方式
- 基于Redis或者DB的自增ID生成方式
- 特殊的规则生成唯一ID
具体的实现方法跟优缺点可以参考之前的一篇博文:分布式唯一 ID 解析
在IM系统中需要唯一Id的地方主要是:
- 会话ID
- 消息ID
消息ID
我们来看看在设计消息ID时需要考虑的三个问题。
消息ID不递增可以吗
我们先看看不递增的话会怎样:
- 使用字符串&#