如何保证消息队列高可用?¶
一、Broker 高可用¶
1. 主从复制¶
- 同步复制:主写成功等至少一个从写成功才返回。数据不丢,但延迟高。
- 异步复制:主写成功立即返回,从异步同步。性能高,但主挂可能丢少量消息。
- 半同步:至少一个从收到即返回,平衡。
2. 自动故障转移¶
- RocketMQ:Dledger / Controller 模式,主挂自动选从。
- Kafka:KRaft(去 ZooKeeper)模式,Controller 选举。
- RabbitMQ:镜像队列 / Quorum Queue。
二、生产端高可用¶
1. 发送重试¶
producer.send(msg, new SendCallback() {
public void onSuccess(SendResult r) {}
public void onException(Throwable e) {
// 重试
}
});
2. 同步刷盘 / 异步刷盘¶
- 同步刷盘:消息写磁盘才返回,不丢但慢。
- 异步刷盘:写 Page Cache 即返回,快但宕机丢数据。
金融场景用同步刷盘,普通业务用异步。
三、消费端高可用¶
1. 集群消费 + Rebalance¶
一个消费组多个实例,Queue 自动分配到不同实例。某实例挂了,Queue 重新分配给其他实例。
2. 手动 ACK¶
处理完业务再 ACK;异常不 ACK,MQ 会重投。
3. 死信队列¶
多次消费失败的消息进 DLQ,避免一直重试阻塞。
四、消息不丢的三段保障¶
- 生产端:发送成功确认 + 失败重试。
- Broker:持久化 + 主从复制。
- 消费端:处理完再 ACK,业务幂等。
五、消息不重复¶
MQ 保证 At least once,所以可能重复。消费端必须幂等:
- 唯一业务 ID + Redis 去重。
- 数据库唯一索引。
- 状态机:已处理状态直接跳过。
六、监控与运维¶
- 堆积监控:
consumer_lag。 - 失败率、重试率。
- Broker 磁盘、网络。
- 定期巡检死信队列。
高频追问
- Kafka 高可用靠 Partition 多副本 + ISR(In-Sync Replicas)。
- RocketMQ 主从同步,主写从读,主挂不自动切(DLedger 后支持自动选主)。