2026/3/30 23:34:10
网站建设
项目流程
海关做预归类的网站,重庆大渡口营销型网站建设公司哪家专业,音乐网页制作素材,网站怎么做最吸引人视频看了几百小时还迷糊#xff1f;关注我#xff0c;几分钟让你秒懂#xff01; 在使用 RabbitMQ 时#xff0c;你是否遇到过这些问题#xff1a;
消息处理失败后直接丢失#xff0c;无法排查#xff1f;消费者异常导致消息无限重试#xff0c;CPU 打满#xff1f;业…视频看了几百小时还迷糊关注我几分钟让你秒懂在使用 RabbitMQ 时你是否遇到过这些问题消息处理失败后直接丢失无法排查消费者异常导致消息无限重试CPU 打满业务超时订单没被取消用户投诉这时候死信队列Dead Letter Queue, DLQ就是你的“消息保险箱”和“故障分析室”本文将用真实业务场景 Spring Boot 代码 正反案例 注意事项带你彻底掌握死信队列的正确用法。一、什么是死信队列 定义当消息满足以下任一条件时会被 RabbitMQ 自动路由到死信交换机DLX进而进入死信队列DLQ消息被拒绝basic.reject或basic.nack且requeuefalse消息 TTL 过期Time-To-Live队列达到最大长度x-max-length。 死信队列本质是一个普通队列只是专门用来存放“无法正常处理”的消息。二、5 大核心使用场景附真实案例✅ 场景 1失败消息隔离 人工干预最常用问题消费者处理消息时抛出异常如果直接丢弃业务损失无法挽回如果无限重试又会拖垮系统。解决方案将失败消息转入 DLQ后续人工或定时任务处理。案例支付回调处理失败支付宝回调消息解析失败不应丢弃否则订单状态不一致转入 DLQ运维后台可手动重试或修复。✅ 场景 2延迟/定时任务替代 Redis ZSet问题需要 30 分钟后检查订单是否支付未支付则自动取消。传统做法用 Redis 定时扫描复杂且不准。RabbitMQ 方案利用TTL 死信队列实现精准延迟。流程发送消息到order.delay.queue设置x-message-ttl180000030分钟TTL 到期后消息自动进入 DLQ即order.cancel.queue消费者监听 DLQ执行取消逻辑。✅ 优势无需轮询资源消耗低精度高。✅ 场景 3防止消息无限重试保护消费者问题消费者因 bug 导致消息一直处理失败 → 无限 requeue → CPU 100% → 服务雪崩。解决方案设置最大重试次数超限后转入 DLQ。实现方式在消息 header 中记录retry_count消费者每次失败 1达到阈值如 3 次后nack(requeuefalse)消息进 DLQ。✅ 场景 4流量削峰中的消息丢弃策略问题高峰期队列堆积 100 万条但系统只能处理最新请求旧消息已无意义如股票行情。解决方案设置x-max-length10000超出部分自动进入 DLQ或直接丢弃。⚠️ 注意需配合x-overflowreject-publish-dlx才会进 DLQ。✅ 场景 5灰度发布中的异常流量捕获问题新版本消费者上线后部分消息格式不兼容导致处理失败。解决方案灰度队列配置 DLQ快速捕获异常消息不影响主链路。三、Spring Boot 实战延迟订单取消完整代码✅ 第一步声明延迟队列 死信队列Configuration public class DlqConfig { // 延迟队列带 TTL public static final String ORDER_DELAY_QUEUE order.delay.queue; // 死信队列实际消费队列 public static final String ORDER_CANCEL_QUEUE order.cancel.queue; // 死信交换机 Bean public DirectExchange dlxExchange() { return new DirectExchange(dlx.exchange); } // 死信队列 Bean public Queue cancelQueue() { return QueueBuilder.durable(ORDER_CANCEL_QUEUE).build(); } // 绑定死信队列 Bean public Binding cancelBinding() { return BindingBuilder.bind(cancelQueue()) .to(dlxExchange()) .with(order.cancel); } // 延迟队列关键设置 TTL 和 DLX Bean public Queue delayQueue() { return QueueBuilder.durable(ORDER_DELAY_QUEUE) .withArgument(x-message-ttl, 180000) // 3分钟测试用 .withArgument(x-dead-letter-exchange, dlx.exchange) .withArgument(x-dead-letter-routing-key, order.cancel) .build(); } Bean public DirectExchange delayExchange() { return new DirectExchange(delay.exchange); } Bean public Binding delayBinding() { return BindingBuilder.bind(delayQueue()) .to(delayExchange()) .with(order.create); } }✅ 第二步生产者发送延迟消息Service public class OrderService { Autowired private RabbitTemplate rabbitTemplate; public void createOrder(String orderId) { // 1. 创建订单状态待支付 saveOrder(orderId, PENDING); // 2. 发送延迟消息3分钟后检查 rabbitTemplate.convertAndSend( delay.exchange, order.create, orderId ); } }✅ 第三步消费者处理超时订单Component public class OrderCancelConsumer { RabbitListener(queues DlqConfig.ORDER_CANCEL_QUEUE) public void handleTimeoutOrder(String orderId) { Order order getOrder(orderId); if (PENDING.equals(order.getStatus())) { // 取消订单 cancelOrder(orderId); System.out.println(Order orderId cancelled due to timeout.); } // 已支付则忽略 } }✅效果订单创建后 3 分钟自动检查未支付则取消全程无需定时任务❌ 反例这些 DLQ 用法很危险反例 1DLQ 不消费只堆积// ❌ 错误DLQ 也需要消费者 Bean public Queue dlq() { return QueueBuilder.durable(my.dlq).build(); // 但没人监听 }后果DLQ 消息无限堆积最终撑爆 RabbitMQ 内存✅ 正确做法必须为 DLQ 配置消费者人工处理 or 自动修复。反例 2所有异常都进 DLQ不分类型RabbitListener(queues order.queue) public void handle(String msg) { try { process(msg); } catch (Exception e) { channel.basicNack(tag, false, false); // 全部进 DLQ } }问题网络抖动等临时异常也被永久隔离无法自动恢复。✅ 正确做法区分异常类型业务异常如参数错误→ 进 DLQ临时异常如 DB 连接失败→ requeue 重试。⚠️ 关键注意事项DLQ 必须持久化QueueBuilder.durable(xxx.dlq).build()否则 RabbitMQ 重启后消息丢失监控 DLQ 长度设置告警rabbitmq_queue_messages{queue*.dlq} 0定期清理已处理消息不要用 DLQ 替代日志DLQ 是可恢复的消息存储不是错误日志。建议同时记录日志 进 DLQ。延迟队列的精度问题RabbitMQ 延迟是单队列共享 TTL不适合多延迟时间场景。如需多种延迟5s/30s/1h建议用插件rabbitmq-delayed-message-exchange。DLQ 消费者也要限流避免 DLQ 消费过快导致下游压力。四、总结DLQ 使用 Checklist✅必须做延迟/失败消息进 DLQDLQ 队列持久化为 DLQ 配置消费者监控 DLQ 消息数并告警。❌禁止做DLQ 只建不消费所有异常无差别进 DLQ用 DLQ 存储非消息数据。记住死信队列不是“垃圾桶”而是“急诊室”——消息进去是为了被抢救而不是被遗忘视频看了几百小时还迷糊关注我几分钟让你秒懂