
1) 【一句话结论】采用“客户端-服务端-分布式消息队列(Kafka,配置acks=all、3副本、日志保留7天)-持久化存储(MySQL按时间分库分表+Redis Cluster缓存)”的多层架构,结合WebSocket长连接(30秒心跳+自动重连),消息先入Kafka再推WebSocket,保障实时性;通过Kafka持久化、副本同步、消费重试保障可靠性;分片+负载均衡实现百万级扩展;消息不丢失通过Kafka持久化+消费重试,不重复通过消息ID+Redis SETNX。
2) 【原理/概念讲解】老师:设计百万级实时消息系统,核心要解决实时性、可靠性、可扩展性。
3) 【对比与适用场景】
| 对比项 | Kafka(消息队列) | MySQL(持久化存储) | WebSocket(实时通信) |
|---|---|---|---|
| 定义 | 分布式流处理平台,支持高吞吐、持久化、多分区 | 关系型数据库,支持事务、持久化、分库分表 | 双向长连接通信协议,低延迟双向通信 |
| 特性 | 高吞吐、持久化(acks=all)、分区顺序保证、副本因子3、日志保留7天、消费重试 | 事务支持、持久化、读写分离、分库分表、写入性能受限于分片 | 低延迟、维护长连接、需处理连接异常(30秒心跳+自动重连) |
| 使用场景 | 消息缓冲、持久化、顺序保证、重试机制 | 长期消息存储、历史记录、读写分离 | 实时消息推送、秒级响应 |
| 注意点 | 需配置acks=all、副本因子、日志保留时间;消费延迟可能高 | 写入性能受限于分片,需读写分离;事务操作影响性能 | 需维护长连接,处理连接异常(如心跳超时自动重连) |
4) 【示例】
伪代码示例(客户端发送消息流程,含Kafka分区、MySQL分库分表、Redis Cluster):
// 客户端发送消息请求
POST /send_message
{
"from": "user1",
"to": "user2",
"content": "hello",
"timestamp": 1672531200
}
// 服务端处理流程
1. 验证用户身份
2. 封装消息对象,写入Kafka主题(如"chat_messages"),分区按用户ID哈希(分区ID = hash("user2"))
3. 同时写入Redis Cluster(key: "chat:user2:recent",value: 消息内容)
4. 写入MySQL(表名:chat_messages_2023_07,按时间分表,插入消息)
5. 返回成功响应
// 消费端(用户2的客户端)拉取消息
GET /fetch_messages?to=user2
// 客户端通过WebSocket接收消息,优先从Redis Cluster缓存,若缓存无,从MySQL按时间分表查询(如2023-07-01数据)
// Redis Cluster通过Pipelining批量读取,提升高并发性能
5) 【面试口播版答案】(约90秒):
“面试官您好,针对百万级用户实时消息系统,我的设计核心是构建分层、高可靠的架构。首先,实时性方面,采用WebSocket长连接,客户端与服务端保持持续通信,消息秒级推送到客户端,同时设置30秒心跳检测,断线后自动重连(客户端示例:定时发送心跳包,超时后重连)。然后,可靠性方面,引入Kafka作为消息队列,配置acks=all(确保服务端确认后写入磁盘)、3副本(数据冗余)、日志保留7天(持久化),所有消息先入队列再推WebSocket,保障服务端故障时消息不丢失。可扩展性上,Kafka按用户ID哈希分片(每个分区对应部分用户),通过负载均衡分发请求;MySQL按时间分库分表(如按月),读写分离(主从复制),支持横向扩展。消息不丢失的保障:Kafka持久化+副本同步(若某副本故障,其他副本恢复后补发);消费失败后最多重试3次,超时后标记为失败。不重复则通过消息ID唯一标识,消费端检查Redis SETNX(成功则处理,失败则跳过)。这样既能保证实时性,又能兼顾可靠性与可扩展性。”
6) 【追问清单】
7) 【常见坑/雷区】