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

设计一个支持百万级用户同时在线的实时消息系统(如微信聊天),请阐述系统架构设计,包括消息存储、路由、高可用与容灾策略。

Tencent软件开发-测试开发方向难度:困难

答案

1) 【一句话结论】

采用分布式消息队列(Kafka)解耦生产与消费,结合Redis缓存(实时消息)和分片MySQL(历史消息),通过用户ID哈希路由消息到分区,集群部署实现高可用与容灾,旨在支撑百万级用户并发下的低延迟、高可用。

2) 【原理/概念讲解】

(用老师口吻,解释核心组件逻辑,避免空话,用类比辅助理解)

  • 消息队列(Kafka):分布式、高吞吐、持久化系统,像“消息快递中转站”。生产者(发消息的用户)将消息发到中转站,消费者(收消息的用户)从中转站取。生产者按用户ID哈希到特定分区(如用户A的ID哈希到分区0,用户B到分区1),避免跨分区消费,减少网络开销。
  • 消息路由:Nginx+负载均衡负责将请求分发到Kafka集群节点,生产者客户端根据用户ID计算哈希值,选择目标分区(如用户A的ID哈希到分区0,用户B到分区1),确保消息按用户分组处理。
  • 消息存储:
    • 实时消息:用Redis(内存数据库),列表结构存储消息(如聊天消息列表,最近100条),支持秒级拉取,低延迟。
    • 历史消息:用分片MySQL(关系型数据库),按用户ID范围分片(如哈希分片),支持大数据量存储,事务支持。
  • 高可用与容灾:
    • Kafka集群多副本(如3副本),确保单节点故障时数据不丢失;
    • MySQL主从复制(主写从读,主从切换);
    • Redis集群(哨兵/集群模式),数据持久化(RDB/AOF);
    • 应用多实例(负载均衡),避免单点压力。

3) 【对比与适用场景】

存储方案定义特性使用场景注意点
Redis(缓存)内存数据库,支持列表/哈希等数据结构低延迟(毫秒级),高并发,内存存储,持久化可选实时消息拉取(如聊天消息列表,最近100条,秒级响应)依赖内存,数据易丢失(需持久化),不适合存储大量历史数据
MySQL(分片)关系型数据库,支持事务事务支持,持久化,可水平分片历史消息存储(按时间或用户ID分片,支持复杂查询如按时间倒序)分片后查询复杂(需路由),事务跨分片困难,写入延迟较高
MongoDB(分片)NoSQL文档数据库弹性扩展,文档模型,索引支持消息元数据(如消息ID、时间戳)写入延迟较高,查询性能依赖索引,不适合高并发写入

4) 【示例】

伪代码展示用户A发送消息给用户B:

  1. 生产者(A端):计算用户A的ID哈希值,选择Kafka分区0,发送消息到主题“chat:userIdA”。
    # 生产者代码
    import kafka
    producer = kafka.KafkaProducer()
    msg = {"to": "userIdB", "content": "hello", "timestamp": 1672531200}
    producer.send("chat:userIdA", value=msg.encode())
    
  2. 消费者(B端):订阅主题“chat:userIdA”,消费消息后存入缓存与数据库。
    # 消费者代码
    consumer = kafka.KafkaConsumer("chat:userIdA")
    for msg in consumer:
        # 存入Redis(实时消息)
        redis.rpush("chat:userIdB", msg.value.decode())
        # 存入MySQL(历史消息)
        db.insert("chat_history", user_id="userIdB", content=msg.value.decode(), time=msg.timestamp)
    

5) 【面试口播版答案】

(约90秒,自然表达)
“面试官您好,设计百万级实时消息系统,核心是构建分布式解耦架构。首先,消息路由通过Nginx负载均衡,根据用户ID哈希到Kafka不同分区,避免单点压力。消息队列用Kafka,保证高吞吐。存储分两步:实时消息用Redis缓存(列表结构存储,支持秒级拉取最近100条),历史消息用分片MySQL(按用户ID范围分片,支持大数据量存储)。高可用方面,Kafka集群多副本(3副本),MySQL主从复制,Redis集群模式,应用多实例部署。容灾策略包括消息持久化(Kafka日志持久化)、主从切换(MySQL)、缓存持久化(Redis RDB/AOF)。同时,通过ACK机制(生产者等待所有副本确认)、重试策略(指数退避)和幂等性处理(消息ID唯一+消费状态检查)保障消息可靠性,延迟控制通过多消费者并行消费、缓存预热(启动时加载用户消息列表)和批量写入(每批100条消息)优化。”

6) 【追问清单】

  1. 问:如何保证消息不丢失?
    • 回答要点:Kafka多副本(至少3副本),生产者发送后等待所有副本ACK,消费端ACK确认,失败后指数退避重试。
  2. 问:消息延迟如何控制?
    • 回答要点:多消费者并行消费(每个分区一个消费者实例),缓存预热(提前加载用户消息列表到Redis),批量写入(减少I/O,如每批100条消息)。
  3. 问:如何处理消息幂等?
    • 回答要点:消息ID唯一(UUID),消费端检查消息是否已处理(如数据库记录消费状态或Redis SETNX),避免重复消费。
  4. 问:跨地域部署如何设计?
    • 回答要点:多数据中心,消息队列分区域部署(如华东、华南集群),数据库分片跨区域(如ShardingSphere多节点),缓存数据复制(Redis集群跨区域同步)。
  5. 问:历史消息查询性能?
    • 回答要点:MySQL按时间或用户ID建索引(如时间降序,用户ID),分片后查询需路由(根据时间范围选择分片),支持分页查询(最近30天消息)。

7) 【常见坑/雷区】

  1. 单点消息队列:未集群部署,导致单节点故障影响全局。
  2. 未分片存储:关系型数据库单库存储,写入/查询瓶颈,无法支撑百万级数据。
  3. 消息路由错误:未按用户ID哈希到分区,导致跨分区消费,增加网络开销。
  4. 缺少消息丢失保障:仅内存存储(如Redis无持久化),消息丢失风险高。
  5. 未考虑幂等:重复消费导致数据错误(如重复发送消息,或消息状态重复更新)。
51mee.com致力于为招聘者提供最新、最全的招聘信息。AI智能解析岗位要求,聚合全网优质机会。
产品招聘中心面经会员专区简历解析Resume API
联系我们南京浅度求索科技有限公司admin@51mee.com
联系客服
51mee客服微信二维码 - 扫码添加客服获取帮助
© 2025 南京浅度求索科技有限公司. All rights reserved.
公安备案图标苏公网安备32010602012192号苏ICP备2025178433号-1