Design Message System

Design Message System

1. Scenario

Message一般是realtime所以对latency要求高,相对于Availability而言,Consistency更加重要

Message System一般支持以下几个功能:

  • 用户发送信息

  • 通讯录 contacts

  • 提供1-1 chat和group chat

  • 查看用户在线状态

2. Storage

a. DB Schema

  • Message Table: {message_id, chat_id, user_id, content, created_at}, Message由于数据量很大,而且写非常多,所以用Nosql更好。

  • Chat Table: {userid, chat_id, participants_ids, participants_hash, created_at, updated_at}, 其中participants_ids的数据类型是string,本质上是序列化后JSON, 而participant_hash是用来防止建立重复的group chat.当用户建立一个group chat时,我们将所有在group的participants转成一个participants hash,如果participants hash存在,则直接返回之前建立了的group chat

b. 建立index(获取前500个group的data)

Chat table要同时index by user_id, cha_tid, participants_hash和updated_time, 由于NoSQL对multi indexes支持不是很好,所以Chat Table用SQL更好

c.区分已读和未读信息

3. Service

a. Message Service 负责信息管理

b. Push Service 负责实时推送信息给接收者

4. Scale

a. Message Table本身用NoSQL存,自带scale属性。对于Chat Table,我们可以用user id做sharding

b. 如何减少latency

利用socket连接push service,当有人发消息时,message service收到信息,然后通过push service发送消息。如果一个用户长期不活跃(比如10分钟),则断开连接,释放端口.

c. 如何支持group chat

在一个group chat中,我们只需要发送消息给在线的用户即可。但只有push service才知道哪些用户在线,所以在message service接收信息,发给push service之前,我们加上channel service。 当用户上线时,message service找到用户所订阅的group, 通知用户完成订阅。当用户掉线的时候,push service知道用户掉线后, 则通知channel service从该用户所属的频道移除

channel的数据存储可以直接放在内存,维护一个类似Map<channelId, Set<UserId>> 的hashmap即可

d. 在线状态更新:

Pull Model:用户上线后,每隔一定时间(比如5秒)向server heartbeat一次, 如果server隔很久没有收到一个用户的heartbeat信息,则可以认为该用户已经下线。在线的用户可以每隔一段时间向server查询好友的在线状态

Last updated