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

设计一个支持百万级用户同时在线的实时消息系统(如微信聊天),需要考虑消息的实时性、高可用、可扩展性。请从消息路由、存储、同步、高可用、容灾等方面阐述系统设计思路。

Tencent软件开发-后台开发方向难度:中等

答案

1) 【一句话结论】
采用分布式消息队列(Kafka)作为消息中转,结合Redis缓存实时消息状态与MySQL持久化历史消息,通过用户ID到服务器的映射实现高效路由,并借助集群、备份方案保障高可用与容灾,确保百万级并发下的实时性与可靠性。

2) 【原理/概念讲解】
老师:设计百万级实时消息系统,核心是解决“消息路由、存储、同步、高可用、容灾”这几个关键问题。首先看消息路由:用户ID(如“user123”)需要映射到具体服务器(如Server1),避免单点压力。这里用一致性哈希,但为了防热点,引入虚拟节点(比如把用户ID哈希后,每个物理节点对应多个虚拟节点,分散负载)。然后是消息存储:分为“实时消息”和“历史消息”。实时消息需要快速推送,所以用Redis(内存缓存,支持发布/订阅,比如消息ID、内容、发送时间)作为缓存层,同时通过Kafka持久化(防止消息丢失,比如设置acks=all,确保至少一次投递)。历史消息则存入MySQL(按时间分表,比如按月分区,支持历史查询)。接下来是消息同步:用户A发消息给B,服务器将消息写入Kafka主题(如“userA_to_userB”),消息内容为JSON(包含发送者、接收者、内容、时间)。Kafka消费者(部署在目标服务器)消费消息后,将消息存入Redis(比如用户B的会话缓存),然后通过WebSocket长连接推送给B的客户端,保证实时性。高可用方面,服务器部署集群(多台服务器),消息路由用Nginx+负载均衡(比如轮询或加权轮询),数据库做主从复制(主库写,从库读,提升读写分离),Redis用集群模式(避免单点故障)。容灾则是数据备份,比如MySQL异地备份(RDS异地灾备),Kafka日志备份(多副本存储),服务器故障时自动切换到备用节点(比如通过ZooKeeper或Consul管理节点状态)。

3) 【对比与适用场景】

组件定义特性使用场景注意点
Kafka分布式消息队列高吞吐、持久化、可扩展、支持事务实时消息、日志处理、解耦系统需要持久化磁盘,启动慢,消息延迟较高
Redis内存数据库高速缓存、支持发布/订阅、事务实时消息状态、会话管理依赖内存,持久化成本高,单点故障风险
MySQL关系型数据库ACID、事务支持、结构化存储历史消息持久化、数据持久化扩展性差(写入慢),需分表分库
Nginx负载均衡器高性能、灵活配置消息路由、负载均衡需要合理配置负载策略(如虚拟节点映射)

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

// 用户A调用API
POST /send?to=userIdB&msg=hello

// 服务器处理流程
1. 接收请求,解析用户A和用户B的ID。
2. 通过一致性哈希+虚拟节点,将用户A的路由到Server1(消息路由)。
3. 将消息写入Kafka主题(如userA_to_userB),消息内容为JSON:{"sender": "userA", "receiver": "userB", "content": "hello", "time": 1678888888}。
4. Server1消费Kafka消息,将消息存入Redis(key为用户B的会话ID,如"session_userB",value为消息内容)。
5. 通过WebSocket连接推送消息给用户B的客户端。
6. 同时,将消息写入MySQL历史表(表history,字段:sender, receiver, content, time, create_time,按月分区)。

5) 【面试口播版答案】
“设计百万级实时消息系统,核心思路是分层架构:消息路由用用户ID到服务器的映射,实时消息用Kafka中转+Redis缓存,历史消息存MySQL。高可用通过集群,容灾用备份。比如用户A发消息给B,先路由到A的服务器,写入Kafka,再推给B的客户端,同时存历史。具体来说,用户发送消息时,服务器将消息写入Kafka,通过负载均衡路由到目标服务器,服务器消费后用WebSocket推送,同时持久化历史。高可用方面,服务器集群+数据库主从,Redis集群,避免单点故障。容灾则通过数据备份,比如MySQL异地备份,Kafka日志备份,确保故障后能快速恢复。另外,消息丢失通过Kafka的acks=all保障,路由热点用虚拟节点分散,历史查询按时间分表加索引,提升效率。”

6) 【追问清单】

  • 问题1:消息丢失怎么办?
    回答要点:采用Kafka持久化存储,设置生产者acks=all,确保消息至少被消费一次,避免丢失。
  • 问题2:路由热点问题如何解决?
    回答要点:使用一致性哈希+虚拟节点,将用户ID映射到多个虚拟节点,分散到不同服务器,避免单点负载过高。
  • 问题3:历史消息查询效率如何保障?
    回答要点:历史消息按时间分表(如按月分区),使用时间范围索引,分页加载,避免全表扫描。
  • 问题4:高可用下Redis与Kafka数据一致性如何保障?
    回答要点:通过消息确认机制(如Kafka acks=all)和事务操作,确保Redis缓存与Kafka消息同步,避免数据不一致。
  • 问题5:消息重发机制如何避免重复推送?
    回答要点:推送失败时设置重试次数(如3次)和间隔时间(如指数退避),同时Redis存储消息ID,避免重复消费。

7) 【常见坑/雷区】

  • 数据一致性风险:若Redis与Kafka未做同步,可能导致缓存与消息不一致(如Redis有消息但Kafka未消费)。需通过事务或消息确认机制保障。
  • 路由热点问题:仅用一致性哈希可能导致部分服务器负载过高,需引入虚拟节点分散负载。
  • 消息重发导致重复推送:推送失败时直接重发可能导致重复消息,需设置幂等性(如Redis存储消息ID)。
  • 历史消息存储成本:百万级用户历史消息量巨大,需考虑数据归档策略(如按时间删除旧数据),避免存储成本过高。
  • 高可用下的故障切换:服务器故障时需快速切换到备用节点,需通过ZooKeeper/Consul管理节点状态,确保服务不中断。
51mee.com致力于为招聘者提供最新、最全的招聘信息。AI智能解析岗位要求,聚合全网优质机会。
产品招聘中心面经会员专区简历解析Resume API
联系我们南京浅度求索科技有限公司admin@51mee.com
联系客服
51mee客服微信二维码 - 扫码添加客服获取帮助
© 2025 南京浅度求索科技有限公司. All rights reserved.
公安备案图标苏公网安备32010602012192号苏ICP备2025178433号-1