常见分布式应用系统设计图解(一):即时消息系统

在自己学习各种各样软件系统,特别是分布式系统的过程中,我做了一些笔记,有许多常见的、经典的系统,是非常值得学习和总结的。它们数量不算多,但具有典型意义,可能这样的系统也就十几个。

我在回顾这些笔记的时候发现,有时候一张简单的图,包含最核心的几个设计,就可以很大程度地帮助理解和记忆。所以我想把这些笔记和图解的结合通过文章的形式发出来,预计每篇文章都很短,基本上一张图,加上一点说明性的文字。

Disclaimer:这些都来自我自己的阅读和理解,肯定有着相当的改变和简化,因此它并不代表任何系统实际的样子。

今天是第一篇,即时消息系统,但是基本上好多即时通讯软件都属于这一类,比如微信,比如 QQ,比如 Facebook Messenger,比如 WhatsApp。

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

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》

668 次阅读

2 thoughts on “常见分布式应用系统设计图解(一):即时消息系统

  1. Channel/Queue 这里可以深入一点, 是类似 kafka 一样的 queue 吗?比如在用户离线的情况下如何处理 queue 里积压的信息?

    1. 我的理解是,和 Kafka 这样的比起来,还是明显有区别的,因为 ChatService 负责所有消息的持久化了,要是这里再做一遍就重复了,这里其实主要还是一个 channel 的功能,消息应该是暂存(缓存)给 PushService 即时读取之用的,因为数据 push 过程对于速率无法保证,那么数据消费的速率也就无法保证,同时数据也可能被多台 PushService 机器使用(比如群聊的情况),因此使用这个 channel 来共享、缓存待推送新鲜数据。为此我给文中增加了一点描述。

      因此离线情况下,消息可以通过其它方式推送,上面的 channel 里面不会积压信息,即便丢失也没有关系,因为消息是持久化在右侧的数据库里面的。等到用户再上线的时候,会发送给 ChatService 一个时间戳(这个戳可以是客户端保存,也可以存放在服务端的用户系统里),这样 ChatService 就可以推送相应的该时间戳之后的积压的消息。

Leave a Reply

Your email address will not be published.

back to top