日常工作总结篇--MQ消息的不丢失
mq消息的丢失,存在三个主要环节:
1、生产者投递
2、磁盘存储
3、消费者拉取消费
1. 生产者投递
- 同步发送:使用同步发送方式,确保消息成功到达Broker(消息中间件服务器)后再返回确认。
- 消息确认机制:启用消息发送的回调机制,只有在收到Broker的成功确认后,生产者才认为消息发送成功。
- 重试机制:如果发送失败,设置合理的重试策略,避免因网络抖动或Broker短暂不可用导致的消息丢失。
2. 磁盘存储
- 持久化存储:将消息写入磁盘进行持久化存储,而不是仅存放在内存中。即使系统宕机,消息也不会丢失。
- 事务日志:启用事务日志功能,确保消息在写入磁盘前被记录下来。
- 副本机制:配置多副本存储,确保主节点故障时,从节点可以接管数据,提高可靠性。
3. 消费者拉取消费
- 自动确认改为手动确认:消费者消费消息后,手动向Broker发送确认信号,确保消息已被成功处理。
- 重复消费容忍:设计消费者逻辑时,确保对重复消息具有幂等性,避免因网络问题导致的重复消费。
- 死信队列:对于无法正常消费的消息,将其放入死信队列,便于后续排查和处理。
- 消费失败重试:配置合理的消费失败重试机制,避免因临时错误导致消息丢失。
RabbitMQ 的完整数据流程可以分为以下几个关键步骤,涵盖从生产者发送消息到消费者接收并处理消息的整个过程。以下是详细说明:
1. 生产者投递消息
-
创建交换机(Exchange)和队列(Queue):
- 生产者首先需要声明一个交换机(Exchange),用于路由消息。
- 同时声明一个队列(Queue),用于存储消息。
- 将交换机与队列绑定(Binding),指定路由键(Routing Key)。
-
发送消息:
- 生产者将消息发送到交换机。
- 消息包含以下属性:
delivery_mode=2
:设置为持久化模式,确保消息写入磁盘。- 路由键(Routing Key):用于匹配队列。
- 如果交换机无法找到对应的队列,可以通过
mandatory=true
参数让消息返回给生产者。
-
确认机制:
- 开启 Confirm 模式(
channel.confirmSelect()
),生产者在发送消息后等待 RabbitMQ 的确认。 - 如果收到 ACK,表示消息成功投递到交换机;如果收到 NACK 或超时未收到确认,则重新发送消息。
- 开启 Confirm 模式(
2. RabbitMQ 内部处理
-
消息路由:
- 消息到达交换机后,根据路由键(Routing Key)和绑定规则(Binding Key)匹配目标队列。
- 如果没有匹配的队列,消息会被丢弃或返回给生产者(取决于是否设置了
mandatory=true
)。
-
消息持久化:
- 如果队列和消息都被设置为持久化模式,RabbitMQ 会将消息写入磁盘。
- 队列持久化:通过
queueDeclare
方法设置durable=true
。 - 消息持久化:通过
basicPublish
方法设置MessageProperties.PERSISTENT_TEXT_PLAIN
。
-
镜像队列(可选):
- 如果配置了镜像队列(Mirror Queue),消息会被同步到多个节点,提高高可用性。
- 镜像队列的 HA 策略可以通过命令行工具
rabbitmqctl set_policy
配置。
3. 消费者拉取消费
-
订阅队列:
- 消费者通过
basicConsume
方法订阅队列,开始消费消息。 - 设置
autoAck=false
,关闭自动确认机制,改为手动确认。
- 消费者通过
-
消息分发:
- RabbitMQ 根据消费者的负载均衡策略(如公平分发、轮询等)将消息分发给消费者。
-
消息处理:
- 消费者接收到消息后,执行业务逻辑。
- 如果处理成功,发送 ACK(
basicAck
)通知 RabbitMQ 删除消息。 - 如果处理失败,发送 NACK(
basicNack
)或拒绝消息(basicReject
),可以选择重新入队或放入死信队列。
-
重试机制:
- 如果消费者处理失败,可以配置重试次数,避免因临时错误导致消息丢失。
- 使用 RabbitMQ 的延迟队列功能,将失败的消息重新调度。
4. 异常处理
-
生产者异常:
- 如果生产者发送消息失败,启用重试机制或记录日志报警。
- 结合本地消息表进行补偿,定期检查未确认的消息并重新发送。
-
RabbitMQ 异常:
- RabbitMQ 崩溃后,持久化的消息会从磁盘恢复。
- 配置镜像队列或多节点集群,提高系统高可用性。
-
消费者异常:
- 如果消费者在处理消息时崩溃,未确认的消息会被重新分配给其他消费者。
- 使用死信队列捕获无法处理的消息,便于后续排查。
5. 可靠性保障措施
-
事务机制(不推荐):
- 生产者开启事务模式(
channel.txSelect
),提交事务前阻塞等待 RabbitMQ 确认。 - 性能较差,一般不建议使用。
- 生产者开启事务模式(
-
Confirm 和 Return 机制:
- Confirm:确保消息成功投递到交换机。
- Return:捕获无法路由到队列的消息,返回给生产者。
-
消费者手动 ACK:
- 确保消息处理完成后才删除,避免因消费者崩溃导致消息丢失。
-
高可用架构:
- 配置 RabbitMQ 集群,使用镜像队列或多节点部署。
- 配合负载均衡器(如 HAProxy)实现故障切换。
总结
RabbitMQ 的完整数据流程如下图所示:
深色版本
生产者 → 交换机 → 队列 → 消费者
为了保证消息不丢失,可以从以下几个方面入手:
- 生产者端:启用 Confirm 和 Return 机制,结合重试和补偿机制。
- RabbitMQ 中间件:启用持久化、镜像队列和高可用架构。
- 消费者端:关闭自动确认,采用手动 ACK,并设计幂等性和重试机制。
通过上述措施,可以最大程度地保证消息在整个链路中不丢失。