
采用分布式消息队列(Kafka)解耦生产与消费,结合Redis缓存(实时消息)和分片MySQL(历史消息),通过用户ID哈希路由消息到分区,集群部署实现高可用与容灾,旨在支撑百万级用户并发下的低延迟、高可用。
(用老师口吻,解释核心组件逻辑,避免空话,用类比辅助理解)
| 存储方案 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| Redis(缓存) | 内存数据库,支持列表/哈希等数据结构 | 低延迟(毫秒级),高并发,内存存储,持久化可选 | 实时消息拉取(如聊天消息列表,最近100条,秒级响应) | 依赖内存,数据易丢失(需持久化),不适合存储大量历史数据 |
| MySQL(分片) | 关系型数据库,支持事务 | 事务支持,持久化,可水平分片 | 历史消息存储(按时间或用户ID分片,支持复杂查询如按时间倒序) | 分片后查询复杂(需路由),事务跨分片困难,写入延迟较高 |
| MongoDB(分片) | NoSQL文档数据库 | 弹性扩展,文档模型,索引支持 | 消息元数据(如消息ID、时间戳) | 写入延迟较高,查询性能依赖索引,不适合高并发写入 |
伪代码展示用户A发送消息给用户B:
# 生产者代码
import kafka
producer = kafka.KafkaProducer()
msg = {"to": "userIdB", "content": "hello", "timestamp": 1672531200}
producer.send("chat:userIdA", value=msg.encode())
# 消费者代码
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)
(约90秒,自然表达)
“面试官您好,设计百万级实时消息系统,核心是构建分布式解耦架构。首先,消息路由通过Nginx负载均衡,根据用户ID哈希到Kafka不同分区,避免单点压力。消息队列用Kafka,保证高吞吐。存储分两步:实时消息用Redis缓存(列表结构存储,支持秒级拉取最近100条),历史消息用分片MySQL(按用户ID范围分片,支持大数据量存储)。高可用方面,Kafka集群多副本(3副本),MySQL主从复制,Redis集群模式,应用多实例部署。容灾策略包括消息持久化(Kafka日志持久化)、主从切换(MySQL)、缓存持久化(Redis RDB/AOF)。同时,通过ACK机制(生产者等待所有副本确认)、重试策略(指数退避)和幂等性处理(消息ID唯一+消费状态检查)保障消息可靠性,延迟控制通过多消费者并行消费、缓存预热(启动时加载用户消息列表)和批量写入(每批100条消息)优化。”