系统设计 Lab
聊天后端首先是个连接问题:得追踪上百万条活跃 socket,再把一条消息 fan-out 给所有该收到它的人。
调节并发连接数、消息速率、群组大小、在线比例、历史保留时长、每用户设备数和 region 数。设计会从单台 socket server 演进到带 session registry 的 connection gateway 集群、带 presence service 的路由与 fan-out 层、持久化的 per-user inbox,最后是跨 region 路由加 offline push。
分步讲解
一步一步把它想清楚
要点
常规演进场景
从左到右点击,就是预设的演示路径。每张卡片都会改变 workload 输入。
推荐形态
当前架构路径
Client
Client 保持一条长连接 WebSocket,用来实时收发消息
Connection gateway
WS gateway 终结持久连接,把每条活跃 socket 保存在内存里
Session registry 把每个在线 user/device 映射到持有其 socket 的 gateway 节点
路由 + presence
Router / fan-out 把一次发送展开给每个群成员,并各自路由到对应的 gateway
Presence 追踪谁在线,并传播已送达 / 已读回执
消息存储
消息存储 持久化每条消息,让历史能熬过重启和迟到的同步
Per-user inbox 按收件设备排队消息,直到它重连并拉取
Offline push
Push service 发 APNs/FCM 通知唤醒离线设备,让它们去同步
瓶颈
连接内存
消息 fan-out 速率
Inbox + 历史存储
Presence + 回执开销
跨 region 路由
为什么会变
决策权衡
有出处支撑的规则
这些是模型背后那些经得起时间考验的 system design 论断。而 slider 的具体阈值,则被刻意标注为教学用的假设。
WebSocket 是一条服务端必须保持打开的持久全双工连接
每个聊天 client 都持有一条长连接,所以 gateway 层的规模取决于它能在内存里保持多少条打开的 socket,而不是请求速率。
MDN Web DocsPublish/subscribe 把发送者和消息的众多收件人解耦开
fan-out 给一个群天然就是个 pub/sub 问题:一次 publish 投递给每个 subscriber,router 正是这样把一次发送展开给众多成员的。
Google Cloud Pub/Sub持久化的 message queue 让离线收件人之后还能收到消息
per-user inbox queue 为掉线或多设备用户暂存消息,直到每台设备重连并把它的 queue 抽干。
AWS SQSEnd-to-end encryption 意味着服务端路由的是它读不了的密文
有了 E2EE,服务端能 fan-out 和存储消息,但没法窥探内容,所以服务端的功能只能基于密文和 metadata 来做。
Signal Protocol教学用假设
- 每条活跃 socket 按一份固定的内存预算计费(内核加 app buffer 加 session state);真实成本因技术栈而异。
- fan-out 速率 = 每秒消息数 × 平均群组大小 × 每用户设备数;presence 和回执还会在此之上叠加回传事件。
- 单节点的 gateway、路由、inbox 写入和 presence 预算都是保守的教学数字,不是厂商上限。