知识卡片

360消息系统的六大组件架构

结构图卡

内容

360消息系统(长连接push系统,实时在线数亿量级)由六个职责清晰分离的组件构成。Dispatcher Service根据客户端请求信息,把符合网络和区域条件的一组长连接服务器IP传给客户端,客户端拿到IP后建立长连接、连上Room Service。Room Service是长连接网关,负责hold住用户连接、把用户注册进Register Service,本身还承担接入安全策略、白名单、IP限制等把关工作。Register Service是全局session存储组件,存储和索引用户的相关信息供查询获取。Coordinator Service负责转发用户的上行数据(包括接入方订阅的用户状态回调),并协调各组件间需要异步完成的操作(比如踢用户下线这类需要从Register拿出其他用户信息再做异步处理的场景)。Saver Service是存储访问层,承担对Redis和MySQL的读写,同时提供部分业务逻辑相关的内存缓存(比如广播信息可以在这里缓存);Saver还承担一条重要的防御性策略——因为客户端SDK可能被恶意或意外修改、导致加载了消息却不回复ACK,如果不做处理服务端就不会删除消息,消息会被反复加载形成死循环,Saver在这里做判断和拦截,体现了”客户端永远不可信”这条设计原则。Center Service是提供给接入方的内部API服务器,负责单播/广播接口、状态查询接口,以及运维管理相关的API。用两个例子理解组件如何协作:发一条单播消息时,Center先向Register查询这个用户之前注册的连接通道标识和Room实例地址,再通过对应的Room Service把消息下发给长连接;而全网广播这种更重的工作,需要先把整个任务拆解成一系列子任务分发给所有Center,每个子任务再分别拿到在线和离线的所有用户、批量推给Room Service,这个过程会让整个集群在那一瞬间承受很大压力。此外还有Deployd/Agent Service负责部署管理各进程、收集组件状态信息,以及ZooKeeper和团队自研的Keeper负责整个系统的配置文件管理和简单调度。

结构图

flowchart LR
    A["客户端"] -->|"请求接入IP"| B["Dispatcher Service\n返回符合网络/区域的Room IP组"]
    A -->|"建立长连接"| C["Room Service\n长连接网关,接入安全策略"]
    C -->|"注册用户"| D["Register Service\n全局session存储"]
    E["Center Service\n对接入方的API"] -->|"查询用户连接位置"| D
    E -->|"下发消息"| C
    F["Coordinator Service\n转发上行数据+异步协调"] --- D
    G["Saver Service\n存储访问层\nRedis/MySQL读写"] --- E
    G -.->|"客户端不可信\n防止消息反复加载死循环"| G

参考来源

- 位置:《高可用架构(第1卷)》第1章《高可用架构案例精选》"1.4 如何实现支持数亿用户的长连消息系统:Golang高并发案例"节,"1.4.2 消息系统架构介绍"(源文件:_epub-src/OEBPS/Text/Chapter1_4_3.xhtml) - 结论依据:原文逐一介绍Dispatcher/Room/Register/Coordinator/Saver/Center六个组件的职责,并给出单播和全网广播两个具体工作流程说明组件如何协作,直接支撑本卡片结论与结构图。 - 原始内容:Dispatcher Service根据客户端请求信息,将应网络和区域的长连接服务器的一组IP传送给客户端……比如发一条单播给一个用户,Center先请求register获取这个用户之前注册的连接通道标识、Room实例地址,通过Room Service下发给长连接。