
1) 【一句话结论】
采用“消息队列解耦+多级缓存加速+数据库持久化+实时推送”的分布式架构,通过事务消息、状态同步、缓存预热等工程优化,确保百万级并发下消息延迟<100ms、不丢失,支持消息撤回与历史查询。
2) 【原理/概念讲解】
老师解释,支撑百万级并发,核心是解耦与削峰。
类比:消息队列是消息中转站(解耦),缓存是高速缓存(加速查询),数据库是持久化仓库(不丢失),推送是实时快递员(送达)。
3) 【对比与适用场景】
| 组件 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| Redis(缓存) | 内存数据库,支持高速读写 | 读写延迟低(毫秒级),支持高并发查询,数据易丢失(需持久化) | 未读消息列表、消息预加载、实时状态(如已读标记) | 需配合持久化(如RDB/AOF),避免重启丢失 |
| MySQL(数据库) | 关系型数据库,持久化存储 | 数据持久化,支持复杂事务与查询,读写延迟较高(需优化) | 消息持久化、历史查询、状态管理(如消息状态、用户关系) | 需优化索引、分库分表,降低延迟 |
| 消息队列(如RocketMQ) | 分布式消息系统 | 高吞吐、低延迟、支持事务、持久化 | 解耦发送与处理,确保消息不丢失,支持批量消费 | 需部署多实例,负载均衡 |
4) 【示例】
伪代码展示用户A发送消息给B,撤回的流程:
用户A发送消息给用户B:
INSERT INTO message (sender, receiver, content, send_time)
VALUES ('userA', 'userB', 'hello', NOW())
RPush userB_messages:latest "hello"
EXPIRE userB_messages:latest 300 # 5分钟过期
INCR userB_unread_count
client.send("new_message", {sender: "userA", content: "hello"})
BEGIN TRANSACTION;
DELETE FROM message WHERE id = ? AND sender = ? AND receiver = ?;
COMMIT; # 事务消息确认,确保原子性
LREM userB_messages:latest 0 "hello"
DECR userB_unread_count
client.send("message_retracted", {message_id: ?, sender: "userA"})
5) 【面试口播版答案】
“要设计百万级并发的即时通讯消息系统,核心架构是消息队列(如RocketMQ)解耦发送与处理,多级缓存(Redis)加速查询,数据库(MySQL)持久化,实时推送(WebSocket)保证延迟。消息队列避免用户发送时阻塞数据库,消费端将消息持久化到MySQL,确保不丢失。Redis缓存消息列表和未读数,支持毫秒级查询。推送服务通过WebSocket实时推送,延迟控制在100ms内。历史查询通过按天分片存储(如day_20240101),按时间范围高效查询。关键优化点包括:消息队列部署多实例,通过负载均衡器(如Nginx)分发消息,消费端多线程并行处理;Redis设置5分钟TTL并实现缓存预热(预存热门用户的消息列表);历史表按时间分片+时间索引(时间、用户ID),避免全表扫描;消息撤回时,先通过事务消息删除数据库记录,再更新Redis并通知所有客户端删除本地消息,确保状态一致性。”
6) 【追问清单】
7) 【常见坑/雷区】