51mee - AI智能招聘平台Logo
模拟面试题目大全招聘中心会员专区

设计一个支持百万级用户同时在线的实时消息系统(类似微信消息),需要考虑消息的实时性、可靠性、可扩展性。请描述系统的架构设计、核心组件、数据流转以及如何保证消息不丢失或重复。

Tencent软件开发-移动客户端开发方向难度:中等

答案

1) 【一句话结论】采用“客户端-服务端-分布式消息队列(Kafka,配置acks=all、3副本、日志保留7天)-持久化存储(MySQL按时间分库分表+Redis Cluster缓存)”的多层架构,结合WebSocket长连接(30秒心跳+自动重连),消息先入Kafka再推WebSocket,保障实时性;通过Kafka持久化、副本同步、消费重试保障可靠性;分片+负载均衡实现百万级扩展;消息不丢失通过Kafka持久化+消费重试,不重复通过消息ID+Redis SETNX。

2) 【原理/概念讲解】老师:设计百万级实时消息系统,核心要解决实时性、可靠性、可扩展性。

  • 实时性:用WebSocket长连接,客户端与服务端保持持续通信,消息秒级推送到客户端(类比:类似心跳线,保持连接畅通)。
  • 可靠性:消息“先存后发”,先写入Kafka(配置acks=all,确保服务端确认后写入磁盘;3副本保证数据冗余;日志保留7天保障持久化),服务端确认后返回,即使客户端离线,消息不会丢失,之后上线消费。
  • 可扩展性:Kafka按用户ID哈希分片(每个分区对应部分用户),通过负载均衡分发请求;MySQL按时间分库分表(如按月),读写分离(主从复制),支持横向扩展(类比:把用户消息分成多个“分区抽屉”,每个抽屉对应部分用户,抽屉数量随用户增长可新增节点)。
  • 消息不丢失:Kafka持久化+副本同步(若某副本故障,其他副本恢复后补发);消费失败后重试(最多3次,超时后标记为失败)。
  • 消息不重复:消息ID唯一标识,消费端通过Redis SETNX检查(若成功则处理,失败则跳过);Kafka偏移量管理(确保每条消息只消费一次)。

3) 【对比与适用场景】

对比项Kafka(消息队列)MySQL(持久化存储)WebSocket(实时通信)
定义分布式流处理平台,支持高吞吐、持久化、多分区关系型数据库,支持事务、持久化、分库分表双向长连接通信协议,低延迟双向通信
特性高吞吐、持久化(acks=all)、分区顺序保证、副本因子3、日志保留7天、消费重试事务支持、持久化、读写分离、分库分表、写入性能受限于分片低延迟、维护长连接、需处理连接异常(30秒心跳+自动重连)
使用场景消息缓冲、持久化、顺序保证、重试机制长期消息存储、历史记录、读写分离实时消息推送、秒级响应
注意点需配置acks=all、副本因子、日志保留时间;消费延迟可能高写入性能受限于分片,需读写分离;事务操作影响性能需维护长连接,处理连接异常(如心跳超时自动重连)

4) 【示例】
伪代码示例(客户端发送消息流程,含Kafka分区、MySQL分库分表、Redis Cluster):

// 客户端发送消息请求
POST /send_message
{
  "from": "user1",
  "to": "user2",
  "content": "hello",
  "timestamp": 1672531200
}

// 服务端处理流程
1. 验证用户身份  
2. 封装消息对象,写入Kafka主题(如"chat_messages"),分区按用户ID哈希(分区ID = hash("user2"))  
3. 同时写入Redis Cluster(key: "chat:user2:recent",value: 消息内容)  
4. 写入MySQL(表名:chat_messages_2023_07,按时间分表,插入消息)  
5. 返回成功响应  

// 消费端(用户2的客户端)拉取消息
GET /fetch_messages?to=user2
// 客户端通过WebSocket接收消息,优先从Redis Cluster缓存,若缓存无,从MySQL按时间分表查询(如2023-07-01数据)
// Redis Cluster通过Pipelining批量读取,提升高并发性能

5) 【面试口播版答案】(约90秒):
“面试官您好,针对百万级用户实时消息系统,我的设计核心是构建分层、高可靠的架构。首先,实时性方面,采用WebSocket长连接,客户端与服务端保持持续通信,消息秒级推送到客户端,同时设置30秒心跳检测,断线后自动重连(客户端示例:定时发送心跳包,超时后重连)。然后,可靠性方面,引入Kafka作为消息队列,配置acks=all(确保服务端确认后写入磁盘)、3副本(数据冗余)、日志保留7天(持久化),所有消息先入队列再推WebSocket,保障服务端故障时消息不丢失。可扩展性上,Kafka按用户ID哈希分片(每个分区对应部分用户),通过负载均衡分发请求;MySQL按时间分库分表(如按月),读写分离(主从复制),支持横向扩展。消息不丢失的保障:Kafka持久化+副本同步(若某副本故障,其他副本恢复后补发);消费失败后最多重试3次,超时后标记为失败。不重复则通过消息ID唯一标识,消费端检查Redis SETNX(成功则处理,失败则跳过)。这样既能保证实时性,又能兼顾可靠性与可扩展性。”

6) 【追问清单】

  • 问题1:如何保证消息不重复?
    回答要点:通过消息ID唯一标识,消费端检查Redis SETNX或Kafka偏移量,确保每条消息只处理一次。
  • 问题2:如何处理消息延迟或积压?
    回答要点:消息队列设置多个分区/副本提高吞吐,消费端增加并行度(多线程消费),延迟消息设置重试机制与超时。
  • 问题3:消息存储如何扩展?
    回答要点:短期用Redis Cluster缓存(高并发读写),长期用MySQL分库分表(按时间/用户ID分片),逐步扩展存储节点。
  • 问题4:如何保证跨机房高可用?
    回答要点:消息队列与存储跨机房部署(如Kafka集群+ZooKeeper),服务端多活部署,用户请求通过负载均衡分发。

7) 【常见坑/雷区】

  • 坑1:忽略Kafka持久化参数(如acks=all),导致消息丢失(需配置acks=all确保持久化)。
  • 坑2:WebSocket连接异常处理不具体(未提及心跳、重连),导致消息延迟(需设置30秒心跳+自动重连)。
  • 坑3:Redis缓存未考虑高并发瓶颈(未用Cluster或Pipelining),导致缓存写入性能下降(需Redis Cluster或Pipelining优化)。
  • 坑4:消息不丢失保障仅说“尽量保证”,未说明极端故障下的重传机制(如Kafka消费重试、网络分区处理)(需明确重试机制和副本同步)。
  • 坑5:消息顺序保证未按用户ID分区,导致聊天消息乱序(需Kafka按用户ID哈希分区)。
51mee.com致力于为招聘者提供最新、最全的招聘信息。AI智能解析岗位要求,聚合全网优质机会。
产品招聘中心面经会员专区简历解析Resume API
联系我们南京浅度求索科技有限公司admin@51mee.com
联系客服
51mee客服微信二维码 - 扫码添加客服获取帮助
© 2025 南京浅度求索科技有限公司. All rights reserved.
公安备案图标苏公网安备32010602012192号苏ICP备2025178433号-1