
1) 【一句话结论】
百万级即时消息系统以分布式消息队列(如Kafka)为核心,通过消息确认机制(AT LEAST_ONCE为主,结合Exactly Once事务)、分层存储(MySQL持久化+Redis离线缓存)及消息路由负载均衡(一致性哈希),实现高吞吐、低延迟的实时通信,同时通过事务ID/消息ID去重、7天离线消息LRU清理等机制保障可靠性。
2) 【原理/概念讲解】
老师口吻解释关键组件:
3) 【对比与适用场景】
| 对比项 | Kafka | RabbitMQ |
|---|---|---|
| 核心特性 | 主题+分区+副本(高吞吐、持久化、流处理) | 队列+交换机+绑定(灵活路由、事务支持) |
| 事务支持 | 支持Exactly Once(事务ID,回滚机制) | 支持事务,但复杂度较高,需手动管理 |
| 消息持久化 | 日志文件(磁盘,高可靠性) | 内存+磁盘(可选,默认内存) |
| 消息幂等性 | 通过事务ID/消息ID检查,确保幂等 | 需额外实现幂等性逻辑(如数据库唯一键) |
| 适合场景 | 高吞吐、持久化、流处理(如消息系统、日志) | 基于消息的解耦、可靠投递(如订单、通知) |
| 注意点 | 分区管理复杂,消费需手动提交;需考虑消息积压 | 队列模式灵活,但可能存在消息积压;事务处理开销大 |
4) 【示例】
用户A发送消息给用户B的流程(伪代码):
1. 客户端(A端)调用API:POST /send_message?to_user_id=B&message=Hello&msg_id=uuid-123
2. API网关将请求写入Kafka Topic "chat_messages",分区按user_id哈希(user_id%10),消息包含msg_id
3. 消费者(消息处理服务)消费消息:
a. 检查MySQL中是否存在该msg_id(消息重复检测):若存在,跳过处理
b. 执行数据库事务:插入消息到chat_messages表(发送者、接收者、时间、msg_id)
c. 写入Redis离线消息:key=to_user_id(B),value=消息内容+msg_id
4. 消费者发送ACK给Kafka
5. 若Redis有用户B离线记录,推送服务读取离线消息(按msg_id排序),通过APNs/FCM发送
6. 用户B在线时,从MySQL读取历史消息(按时间倒序),从Redis读取离线消息(按msg_id排序),合并展示
5) 【面试口播版答案】(约90秒)
“面试官您好,设计百万级即时消息系统,核心目标是保证实时性、可靠性和可扩展性。架构上以分布式消息队列(如Kafka)为核心,解耦发送方与接收方,缓冲流量。消息持久化到Kafka,确保服务器重启后恢复。消息确认机制采用AT LEAST_ONCE,通过ACK保证可靠性,若消费者失败则重试。消息路由按用户ID或会话ID,将消息发送到目标队列。存储方面,MySQL持久化历史消息(保证一致性),Redis缓存离线消息(快速推送),推送服务处理离线消息。消息重复检测通过Kafka事务或消息ID去重,离线消息在Redis设置7天TTL并定期LRU清理。消息路由采用一致性哈希避免热点分区,通过增加消费者组数量动态扩容缓解积压。整体支持在线用户实时接收、离线用户后续推送,确保高可用与低延迟。”
6) 【追问清单】
7) 【常见坑/雷区】