Design Whatsapp
Scenario
- 基本功能
- 用户登录注册
- 通讯录
- 用户互发信息
- 群聊
- 用户在线状态
- 其他功能
- 历史消息
- multi device
- 1B 月活跃
- 75% 日活跃 750M
- 计算方便取 100M QPS:
- 每个用户平均每天20条。 100M 20/86400 ~ 20k, peak QPS= 20k 5 = 100k Storage
- 2030bytes(每条)100M = 60G
Service
Message Service - 负责信息管理 Real-time Service - 实时推送
Storage
不能存储在手机上,关机问题
- Message Table (NoSQL)
- 数据量很大,不需要修改,就跟log一样
- Tread Table (SQL) 会话
- 需要同时index by
- owner id + thread id (primary key)
- owner id + updated time (按照更新时间倒序排列)
- NoSQL 对multiple indexes的支持并不好
- 需要同时index by
updated_at 是用来给对话在inbox里排序用的 此时primary key是thread_id + owner_i
Work Solution
- 发消息
- client把消息和接受者的信息发给server
- server为每个接受者(包括发送者自己)创建一条thread
- 创建一条message(with thread_id)
- 接收消息
- 每隔十秒钟找服务器要一下最新的inbox
- new message notification
Scale
Message 是NoSQL,自带Scale Thread可以按照owner_id进行sharding,因为每个client都属于同一个owner
how to speed up (Socket)
- Socket, 通过Push Service提供Socket链接服务,可以与Client保持TCP的长连接。
- 当用户打开App后,就连接上push service中一个属于自己的socket
- 有人发消息的时候,Message Service收到消息,再通过push service把消息发出去。
- 如果有一个用户长期不活跃(10mins),可以断开链接,释放掉网络接口。之后再打开App后,主动pull
- vs Http
- http,只能client向server要data
- socket,server可以push data to client
很多个socket,有时候需要多个push service,shard by user_id
group chat
- 假如有500人,不做优化,则需要一个个发消息,但其实同时只有10人在线,这样当消息到了push server才发现490人没有连上,浪费了490个消息传递
增加一个Channel Service
- 对每个聊天的thread增加一个channel信息。
- user需要先subscribe channel,即用户上线时,web server(message service)找到用户所属的channel,并且通知channel service完成订阅,这样channel就知道哪些channel还有用户。如果用户断线了,则push service会通知channel service从所属的频道里移除
- message service在收到用户发的信息以后,找到对应的channel,把发消息的请求发送给channel service,所以只需要发一条消息
- channel service再找到当前在线的用户,发给push service 吧消息push出去
channel service可以用内存存储数据,因为数据重要程度不高,挂了重启即可。
How to check/update online status
Push
- 告知服务器
- 用户上线的时候,与push service保持socket链接
- 用户下线的时候,告诉服务器断开链接
- server无法知道何时下线
- server 告诉好友
- 用户上下线时候,通知服务器
- server通知好友
- server无法知道何时下线,大部分好友不在线
Pull
- 告知server
- 上线后,client每隔3-5s,heart beat一次
- server告知好友
- 在线的好友,每隔3-5s问server要一次大家的status
- 综上可以每隔10s,talk to server, heart beat and request friends' statuses