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

设计一个支持百万级用户同时在线的实时消息系统(类似微信聊天),需要考虑消息的实时性、可靠性、可扩展性。请从系统架构、消息发送流程、消息存储、扩展性、容错与恢复等方面阐述你的设计方案。

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

答案

1) 【一句话结论】
采用微服务拆分+分布式消息队列(Kafka)+双存储(Redis+MySQL)+客户端长连接的架构,通过组件解耦和水平扩展,保障百万级用户的消息实时性、可靠性与可扩展性。

2) 【原理/概念讲解】
老师:设计百万级用户实时消息系统,核心是解决低延迟、高可用、可扩展三大问题,需通过组件协同实现:

  • 客户端长连接:用WebSocket保持客户端与服务端持续连接,避免每次消息都重新建立连接,减少网络开销与延迟;客户端定期发送心跳(如每30秒一次),避免连接超时断开。
  • 消息队列:如Kafka,作为消息中转站,接收服务端消息并按顺序分发给消费服务,确保消息不丢失,还能水平扩展处理高并发(分区并行处理,副本因子3保证高可用)。
  • 消息存储:
    • 实时消息:用Redis(内存数据库,读写延迟低,支持持久化),用于缓存用户刚发送的消息(如未读消息列表、最新消息),快速读取;采用RDB(每分钟快照)+AOF(追加日志)结合,平衡性能与持久化。
    • 历史消息:用MySQL(关系型数据库),通过事务保证数据可靠,用于存储聊天历史记录(如按时间倒序查询);按时间分表(如按月分表),优化查询性能。
  • 消息路由与确认:服务端根据消息接收者(如用户ID),将消息写入Kafka对应分区(如分区0对应用户B);消费服务处理消息后,向队列发送ACK,若未确认则重试(如3次后丢弃),避免消息丢失。

3) 【对比与适用场景】

组件定义特性使用场景注意点
Redis内存数据库,支持持久化读写延迟低(毫秒级),高并发,支持RDB/AOF持久化实时消息缓存(如未读消息、最新消息)内存有限,需配置持久化避免数据丢失
MySQL关系型数据库事务支持,可靠持久化,支持复杂查询历史消息存储,消息持久化读写延迟较高,不适合实时推送
Kafka分布式消息队列高吞吐,持久化,分区并行,副本因子3消息中转(如消息队列,处理高并发消息)需消费端确认,否则消息重试
RDB/AOFRedis持久化策略RDB:全量快照(分钟级),AOF:追加日志(秒级)平衡性能与持久化RDB恢复快但可能丢失数据,AOF安全但写入慢

4) 【示例】
用户A发送消息给用户B的流程(伪代码):

  1. 客户端A通过WebSocket发送POST请求:
    POST /send_message
    {
      "from": "userA",
      "to": "userB",
      "content": "hello",
      "timestamp": 1678888888
    }
    
  2. 服务端(消息发送服务):
    • 验证用户A身份;
    • 将消息写入Kafka主题chat_messages,分区根据to用户ID(如分区0对应userB)。
  3. 消息推送服务(消费Kafka):
    • 从分区0消费消息;
    • 解析消息,通过WebSocket连接推送至用户B。
  4. 存储处理:
    • Redis:将消息存入userB:messages列表,设置过期时间(如7天);
    • MySQL:事务插入消息记录(from, to, content, timestamp),主键为消息ID。

5) 【面试口播版答案】
面试官您好,针对百万级用户实时消息系统,我的设计核心是通过微服务拆分、分布式消息队列和双存储方案,实现低延迟、高可靠和高扩展。首先,客户端与服务端通过WebSocket建立长连接,并定期发送心跳保持连接。消息发送时,服务端将消息写入Kafka,利用其分区和副本机制保证消息不丢失且可水平扩展。消息消费服务从Kafka读取消息后,通过WebSocket推送给目标用户。消息存储方面,实时消息用Redis缓存(低延迟,支持RDB/AOF持久化),历史消息存MySQL(事务保证数据可靠)。扩展性上,消息队列和存储服务可水平扩展,客户端连接通过负载均衡分发。容错方面,Kafka持久化数据支持服务重启后继续消费,Redis的持久化备份恢复数据。这个方案通过组件解耦和分布式技术,满足百万级用户的实时性和可靠性需求。

6) 【追问清单】

  • 问题1:如何保证消息的实时性?
    回答要点:通过客户端长连接(WebSocket)直接推送,消息队列低延迟消费,减少中间环节。
  • 问题2:消息丢失怎么办?
    回答要点:消息队列持久化,结合消费确认机制,若消息未确认则重试(如3次后丢弃)。
  • 问题3:历史消息查询如何优化?
    回答要点:MySQL按时间分表(如按月分表),索引优化(如按时间倒序),或Redis缓存热点消息(如最近30天消息)。
  • 问题4:扩展性中,如何处理用户数量激增?
    回答要点:消息队列水平扩展(增加Kafka broker节点),存储服务分片(如MySQL分库分表),客户端连接负载均衡(如Nginx)。
  • 问题5:容错时,服务宕机如何恢复?
    回答要点:消息队列的持久化数据,服务重启后从队列未确认的消息继续消费;Redis的RDB/AOF恢复数据。

7) 【常见坑/雷区】

  • 坑1:忽略消息确认机制,导致消息重复或丢失。
  • 坑2:消息存储只考虑Redis,忽略持久化,导致数据丢失。
  • 坑3:客户端长连接管理不当,导致资源浪费或连接超时。
  • 坑4:消息路由复杂,导致延迟或错误推送(如用户ID映射错误)。
  • 坑5:扩展性设计时,未考虑数据分片,导致单点瓶颈。
51mee.com致力于为招聘者提供最新、最全的招聘信息。AI智能解析岗位要求,聚合全网优质机会。
产品招聘中心面经会员专区简历解析Resume API
联系我们南京浅度求索科技有限公司admin@51mee.com
联系客服
51mee客服微信二维码 - 扫码添加客服获取帮助
© 2025 南京浅度求索科技有限公司. All rights reserved.
公安备案图标苏公网安备32010602012192号苏ICP备2025178433号-1