侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1824 篇文章
  • 累计收到 0 条评论

设计支持亿级用户的分布式即时通讯系统

2025-12-11 / 0 评论 / 3 阅读

题目

设计支持亿级用户的分布式即时通讯系统

信息

  • 类型:问答
  • 难度:⭐⭐⭐

考点

分布式架构设计,消息可靠性与顺序保证,在线状态管理,高并发优化,数据一致性

快速回答

核心设计要点:

  • 分层架构:网关层/业务层/存储层分离
  • 消息可靠性:端到端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%)