MyBlog


即时消息系统

<p>[TOC]</p> <h1>概述</h1> <p>微信、QQ等即时通信系统</p> <h1>架构图</h1> <p><img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=22b507dcabec46f113b4e5201c5502b8&amp;file=file.png" alt="" /></p> <h1>流程</h1> <ul> <li>用户发送消息,直接发给 Chat Service,它会做少量的处理并持久化,然后发给一个 channel,每一个对话(thread)都会有一个 channel,这个过程中,它并不关心这个对话有多少人参与(支持群聊)。由于单台机器和客户端的连接数量有限(比如小于 2^16=65536),因此 Notification Service 需要有很多机器,根据用户的 id 来 sharding,它们去订阅自己感兴趣的频道,有新的消息就发送给用户。</li> <li>Notification Service 获取客户端的心跳,保持来自客户端的连接(long polling 或者 socket)为了实时性肯定要用 push 模型。因此它知道用户的当前在线状态,也知道最后一条发送成功消息的时间戳(状态)。这个状态可以用于决定用户离线时消息是否要通过其它方式通知用户。</li> <li>Chat Service 有两个职责,一个是处理发消息的请求,一个是接纳读取历史消息的请求,这两个功能可以分成两个组件,也可以一个组件,我放在一起了。</li> <li>右侧的消息数据库,RDB 往往不太适合,因为消息数量太大,对于一组对话(thread)的展示,需要找到该对话 N 条最近的记录,行数据库效率较低,可以考虑列数据库,比如 HBase。这种方式下,同一 thread 下的消息都是按时序存放在一起的,读的效率非常高,写因为基本是 append,也很方便。</li> <li>用户数据的存储,可以使用 RDB,也可以使用 KV 数据库。 这里面存放的数据库表包括:用户表;对话表;用户对话关联表:二者是 M:N 的关系,并且每个用户都可以有对于特定对话的设置,例如设置对话中的昵称,是否屏蔽消息通知等等。</li> <li>对于图中的 Channel, 它并不是 Kafka 这样的复杂的消息系统,而更像 Chat Service 的一个缓存,它是为了提高多个 Notification Service 获取消息效率而设的,不用担心消息丢失,因为持久化的消息在 Message Storage 中。具体来说,因为数据 push 过程对于速率无法保证,那么数据消费的速率也就无法保证,同时数据也可能被多台 Notification Service 机器使用(比如群聊的情况),因此使用这个 Channel 来共享、缓存待推送新鲜数据。</li> <li>对于用户上线、下线的实现,其实也类似,上线、下线的事件可以推送到一个特定的 Channel 里面。用户的好友,也就是感兴趣的 Notification Service 的个体去订阅消息;还有一种思路是把状态更新到用户表里面,这样所有人都可以查询得到,这后一种方式适合非好友也要查看用户状态的情况。上、下线需要保留缓冲时间,容许一定状态的延迟,没必要,也不应过于实时。</li> </ul>

页面列表

ITEM_HTML