题目
设计支持亿级用户的分布式即时通讯系统
信息
- 类型:问答
- 难度:⭐⭐⭐
考点
分布式架构设计,消息可靠性与顺序保证,在线状态管理,高并发优化,数据一致性
快速回答
核心设计要点:
- 分层架构:网关层/业务层/存储层分离
- 消息可靠性:端到端ACK+重试+离线队列
- 在线状态:Redis集群存储状态+心跳检测
- 消息顺序:发送端单调递增序列号+接收端缓冲排序
- 存储优化:冷热数据分离+消息分片存储
1. 整体架构设计
分层架构:
- 网关层:长连接管理(WebSocket),协议转换,负载均衡
- 业务层:消息路由、状态管理、推送服务(微服务架构)
- 存储层:
- 消息存储:分布式KV(如Cassandra)按(sender_id, receiver_id)分片
- 状态存储:Redis Cluster存储用户在线状态
- 离线消息:RabbitMQ/Kafka分区队列
2. 消息可靠性与顺序保证
消息投递流程:
# 发送端伪代码
def send_message(sender, receiver, content):
seq_num = atomic_incr(sender + ":seq") # 从Redis获取全局递增序列号
msg = {seq: seq_num, content: content}
# 写入消息存储(同步落盘)
storage.save(sender, receiver, msg)
# 推送在线消息
if presence.is_online(receiver):
push_service.send(receiver, msg)
else:
offline_queue.push(receiver, msg) # 进入离线队列可靠性机制:
- 端到端ACK:接收方回复消息ID,超时未ACK触发重试
- 重试策略:指数退避+最大尝试次数(避免网络风暴)
- 离线消息:MQ持久化+消费者幂等处理
顺序保证:
- 发送方生成单调递增序列号(每个会话独立)
- 接收方使用缓冲队列处理乱序(TCP滑动窗口类似)
3. 在线状态管理
Redis存储结构:
# Key: user:status:{user_id}
# Value: { "status": "online", "last_active": 1690000000, "gateway_ip": "10.0.0.1" }关键机制:
- 心跳检测:客户端每30秒发送心跳,更新last_active
- 状态变更:网关监听TCP断开事件,延迟5秒后更新状态(防抖动)
- 状态同步:通过Pub/Sub广播状态变更
4. 高并发优化
- 连接优化:
- 网关层使用Netty实现IO多路复用
- 单机支持10万+长连接(JVM调优+直接内存)
- 读写分离:
- 在线消息直推(不经过存储)
- 历史消息异步写入冷存储(如HBase)
- 流量控制:
- 消息分级(普通/重要)采用不同QoS
- 用户级限流(令牌桶算法)
5. 数据一致性挑战
典型问题与解决方案:
| 场景 | 问题 | 解决方案 |
|---|---|---|
| 多设备登录 | 消息重复接收 | 设备独立序列号+客户端去重ID |
| 分布式存储 | 跨分区消息乱序 | 发送方全局序列号(Snowflake变体) |
| 节点故障 | 状态不一致 | 网关层会话转移+状态重新同步 |
6. 常见错误
- 过度依赖数据库:频繁查询在线状态导致DB瓶颈(应使用缓存)
- 乱序处理不当:仅依赖客户端时间戳排序(需服务端强序列)
- 单点故障:未设计网关无状态化+会话迁移机制
7. 扩展知识
- 消息压缩:Protobuf编码+文本压缩(如zstd)
- 边缘计算:全球部署网关节点,就近接入
- 安全设计:端到端加密(Signal协议)+传输层TLS1.3
- 监控指标:消息端到端延迟(P99<200ms)、在线状态准确率(>99.9%)