主要调研学习Slack和WhatsApp这两个产品的全球化架构,单数据中心或是多数据中心,怎样做架构设计,能够解决异地多活和延迟问题。
Slack
产品定位:面向企业,同类产品如:飞书。
这类产品的消息是会持久存储,并支持搜索。
全球架构
参考几篇文章:
- 流量 101:数据包主要流动:https://slack.engineering/traffic-101-packets-mostly-flow/
- Slack 向蜂窝架构的迁移:https://slack.engineering/slacks-migration-to-a-cellular-architecture/
- Flannel:实现 Slack 规模的应用程序级边缘缓存:https://slack.engineering/flannel-an-application-level-edge-cache-to-make-slack-scale/
- 使用 Vitess 扩展 Slack 的数据存储:https://slack.engineering/scaling-datastores-at-slack-with-vitess/
猜测:
- 数据中心在单一的一个区域,单元化在单一区域实现(多AZ),类比:同城多活。
- 每个区域一个边缘机房,实现用户就近接入,并在边缘区域做一些数据缓存。
一个大致的整体架构:
- 事件不需要存储,走ws连接发送
- 消息需要存储,走api发送
消息
WebApp: 提供Webapp API 来发送消息,会存储消息并将消息推送给AS。
AS:AS 查看此消息中的通道 ID,通过一致的哈希环发现 CS,并将消息路由到托管此通道的实时消息传递的相应 CS。
CS: 当 CS 收到该频道的消息时,它会将消息发送给世界各地订阅该频道的每个 GS。
GS: 每个收到该消息的 GS 都会将其发送到订阅该通道 ID 的每个已连接客户端。
Flannel:缓存客户端启动数据,如用户、频道、机器人等的相关数据,提供查询 API 供客户端根据需要获取。
事件
事件,例如成员加入频道、对方输入中。
客户端:客户端通过websocket 将此消息发送给 GS
GS:GS 查看消息中的通道 ID,并根据一致的哈希环路由到相应的 CS。
CS:CS 发送给世界各地订阅该频道的所有 GS。
GS:向订阅此频道的所有用户websockets 广播事件。
单元化
概念:
- 工作区:包含了系统中的所有其他对象,包括用户、频道、消息、文件、表情符号、应用程序等。对应一个租户。
一个工作区只在一个特定的数据库分片、搜索服务分片、数据库分片上。
分片,其实跟阿里云的单元化架构中的“单元”是一个概念,只是用词不同。
跨组织(工作区)沟通,如何分发和存储消息?
- 数据只存储在发起人所属的工作区的分片中
产品定位:面向C端,同类产品如:微信。也提供像企业微信一样的产品或者能力?
这类产品的消息通常只要确定接收端接收后就会删除,持久存储在客户端实现,客户端删除了消息就不存在了。
架构
参考:
参考文章《Whatsapp 系统架构》和视频《WhatsApp System Design | FB Messenger System Design | System Design Interview Question》,Whatsapp的架构可能如下:
单聊架构
UserService提供用户相关的API,读取用户库。
用户与WebSocketHandler服务创建websocket长连接,用于消息通讯。
WebSocketHandler可无限横向扩展,并且可能位于不同区域机房中。
WebSocketHandler会在进程内维持一份userid->ws连接的缓存,同时也会写到redis,供其它websocket查询。
用户发送消息,WebSocketHandler将消息发给MessageService,以便赞存消息。(直到消息已读才会删除)
- 如果对方用户在线:WebSocketHandler通过redis查询(同时也会将结果缓存到进场内30秒后过期,减少查询),查到对方连接的WebSocketHandler节点的ip,然后将消息转发给此WebSocketHandler,再由WebSocketHandler转发给目标用户。
- 如果对方用户不在线:对方用户上线后,主动拉取未读消息,WebSocketHandler通过MessageService拉取用户的未读消息。
用户发送媒体消息:
- 先调用assets service上传文件。
- 将文件的hash和媒体类型包装成消息发送到WebSocketHandler。
- 剩下的跟普通消息一样。
群聊架构
群聊有单独的群聊服务,并且独立的群数据库。
消息发送:
- 用户a在群x里面发送一条消息到WebSocketHandler。
- WebSocketHandler将消息转发给Message Service。
- Message Service将消息存入DB,然后往kafka发送:用户a在群x发送消息xxx。
- 群聊服务(GroupService)订阅kafka,然后消费消息,将消息推给GroupMessageHandler。
- GroupMessageHandler调用GroupService api查询群x的所有用户的id,然后查询redis,获取在线用户连接的WebSocketHandler。(只需要推给在线用户)
- WebSocketHandler将消息推给客户端。
全球架构
未找到相关资料。。。
老板666啊