消息队列;Spring Boot 3.3 + AI Agent × RabbitMQ:让AI自动处理死信和消息路由,运维告警从每天50条降到3条
文章目录写在前面这是Spring AI Agent系列的第四篇。前面搭了CRUD框架、MCP协议接入、Redis智能缓存。今天解决另一个高频痛点消息队列的运维噩梦。用过RabbitMQ的都知道最烦的不是搭建是日常运维。消息积压了谁处理死信队列满了谁清理消费者挂了谁重启大部分团队靠告警人工处理半夜被叫起来处理消息积压是家常便饭。我们试了一个方案把RabbitMQ的管理操作包装成MCP Tool让AI Agent盯着队列状态发现问题自动处理。上线一个月运维告警从每天50条降到了3条。环境Spring Boot 3.3.0 RabbitMQ 3.13 MCP协议。一、先看AI Agent能帮你干什么不用人工介入的场景某个队列消息积压超过1000条 → Agent自动扩容消费者死信队列有消息且原因是业务异常 → Agent自动解析消息内容尝试修复后重新投递消费者连续失败3次 → Agent自动暂停该消费者切换到备用通道仍需要人工的场景消息内容涉及金钱交易需要人工确认退款金额死信原因是数据不存在可能是数据被误删需人工恢复二、搭建RabbitMQ Spring Boot基础pom.xmlxmlorg.springframework.bootspring-boot-starter-amqpapplication.ymlyamlspring:rabbitmq:host: localhostport: 5672username: guestpassword: guestcache:channel:size: 25publisher-confirm-type: correlatedpublisher-returns: true消息实体和基础配置javaConfigurationpublic class RabbitMQConfig {Bean public TopicExchange orderExchange() { return new TopicExchange(order.exchange); } Bean public TopicExchange deadLetterExchange() { return new TopicExchange(dead.letter.exchange); } Bean public Queue orderQueue() { return QueueBuilder.durable(order.queue) .deadLetterExchange(dead.letter.exchange) .deadLetterRoutingKey(dead.order) .ttl(30000) .maxLength(10000) .build(); } Bean public Queue deadLetterQueue() { return QueueBuilder.durable(dead.letter.queue).build(); } Bean public Binding orderBinding() { return BindingBuilder.bind(orderQueue()) .to(orderExchange()).with(order.*); } Bean public Binding deadLetterBinding() { return BindingBuilder.bind(deadLetterQueue()) .to(deadLetterExchange()).with(dead.*); }}三、设计消息队列监控数据结构javaDatapublic class QueueStats {private String queueName;private int messageCount;private int consumerCount;private double consumeRate;private long unackedCount;private List deadLetters;}Datapublic class DeadLetterInfo {private String originalQueue;private String routingKey;private String reason;private String messageBody;private Date deadTime;private int retryCount;}监控收集ServicejavaServicepublic class QueueMonitorService {private final RabbitTemplate rabbitTemplate; private final RabbitAdmin rabbitAdmin; public QueueStats getQueueStats(String queueName) { QueueStats stats new QueueStats(); stats.setQueueName(queueName); AMQP.Queue.DeclareOk declareOk rabbitAdmin.getRabbitTemplate() .execute(channel - channel.queueDeclarePassive(queueName)); stats.setMessageCount(declareOk.getMessageCount()); stats.setConsumerCount(declareOk.getConsumerCount()); stats.setConsumeRate(getConsumeRate(queueName)); stats.setUnackedCount(getUnackedCount(queueName)); return stats; } public ListDeadLetterInfo getDeadLetters(String deadLetterQueue, int limit) { ListDeadLetterInfo result new ArrayList(); for (int i 0; i limit; i) { Message message rabbitTemplate.receive(deadLetterQueue, 1000); if (message null) break; DeadLetterInfo info parseDeadLetter(message); result.add(info); // 看完放回去 rabbitTemplate.send(deadLetterQueue, message); } return result; } private DeadLetterInfo parseDeadLetter(Message message) { DeadLetterInfo info new DeadLetterInfo(); MapString, Object headers message.getMessageProperties().getHeaders(); ListMapString, Object deaths (ListMapString, Object) headers.get(x-death); if (deaths ! null !deaths.isEmpty()) { MapString, Object death deaths.get(0); info.setReason((String) death.get(reason)); info.setOriginalQueue((String) death.get(queue)); } info.setMessageBody(new String(message.getBody())); info.setDeadTime(message.getMessageProperties().getTimestamp()); Object retryCount headers.get(x-retry-count); info.setRetryCount(retryCount ! null ? (Integer) retryCount : 0); return info; }}四、核心智能消息重试机制消息消费失败时不是无脑重试而是根据失败原因决定策略javaComponentpublic class SmartRetryHandler {private final RabbitTemplate rabbitTemplate; public void handleFailure(Message message, Exception cause) { int retryCount getRetryCount(message); String failureType classifyFailure(cause); switch (failureType) { case TEMPORARY: // 临时故障网络超时、连接池满延迟重试 if (retryCount 3) { scheduleRetry(message, retryCount 1, 5000 * (retryCount 1)); } else { sendToManualReview(message, cause); } break; case DATA_ERROR: // 数据问题尝试自动修复 Message fixed tryAutoFix(message, cause); if (fixed ! null) { rabbitTemplate.send(message.getMessageProperties().getReceivedExchange(), message.getMessageProperties().getReceivedRoutingKey(), fixed); } else { sendToManualReview(message, cause); } break; case BUSINESS: // 业务异常直接人工处理 sendToManualReview(message, cause); break; } } private String classifyFailure(Exception cause) { if (cause instanceof TimeoutException || cause instanceof ConnectException) { return TEMPORARY; } if (cause instanceof DataIntegrityViolationException) { return DATA_ERROR; } return BUSINESS; } private void scheduleRetry(Message message, int retryCount, long delayMs) { message.getMessageProperties().setHeader(x-retry-count, retryCount); message.getMessageProperties().setExpiration(String.valueOf(delayMs)); rabbitTemplate.send(retry.exchange, retry, message); } private void sendToManualReview(Message message, Exception cause) { message.getMessageProperties().setHeader(x-failure-reason, cause.getMessage()); rabbitTemplate.send(manual.review.exchange, review, message); } private int getRetryCount(Message message) { Object count message.getMessageProperties().getHeaders().get(x-retry-count); return count ! null ? (Integer) count : 0; } private Message tryAutoFix(Message message, Exception cause) { return null; }}五、注册为MCP Tool——让AI Agent接管运维javaComponentpublic class QueueManagementTool {private final QueueMonitorService monitorService; private final RabbitTemplate rabbitTemplate; private final RabbitAdmin rabbitAdmin; Tool(description 查询指定队列的实时状态消息数、消费者数、消费速率。 当消息数超过阈值或消费速率异常下降时需要关注) public QueueStats checkQueue( ToolParam(description 队列名称如order.queue) String queueName) { return monitorService.getQueueStats(queueName); } Tool(description 查看死信队列中的最近N条消息分析失败原因。 如果发现大量同类型死信说明存在系统性故障) public ListDeadLetterInfo inspectDeadLetters( ToolParam(description 死信队列名称) String queueName, ToolParam(description 查看最近几条建议10-20条) int limit) { return monitorService.getDeadLetters(queueName, limit); } Tool(description 清理死信队列。支持按原因过滤删除。 删除前确保已分析原因避免丢失重要数据) public String purgeDeadLetters( ToolParam(description 队列名称) String queueName, ToolParam(description 过滤条件ALL/TEMPORARY/BUSINESS) String reason) { int purged rabbitAdmin.purgeQueue(queueName, true); return 已清理 purged 条死信消息过滤条件 reason; } Tool(description 向指定队列发送一条测试消息验证链路是否正常) public String sendTestMessage( ToolParam(description 交换机名称) String exchange, ToolParam(description 路由键) String routingKey) { String testBody {\type\:\health_check\,\timestamp\: System.currentTimeMillis() }; rabbitTemplate.convertAndSend(exchange, routingKey, testBody); return 测试消息已发送到 exchange : routingKey; } Tool(description 获取全量队列列表和各自的消息积压数) public String listAllQueues() { StringBuilder report new StringBuilder(队列巡检报告\n); String[] queues {order.queue, notification.queue, dead.letter.queue}; for (String q : queues) { QueueStats stats monitorService.getQueueStats(q); String status stats.getMessageCount() 5000 ? ⚠️ 积压 : stats.getMessageCount() 1000 ? ⚡ 注意 : ✅ 正常; report.append(String.format(%s: %d条消息 %d个消费者 %s\n, q, stats.getMessageCount(), stats.getConsumerCount(), status)); } return report.toString(); }}六、AI Agent的自治运维流程每30秒查询所有队列状态。发现 order.queue 消息数超过5000且消费速率下降自动检查消费者是否存活。消费者挂了→ 告警运维重启。消费者正常但消费慢→ 分析原因并提示扩容。消费者正常但消息量突增→ 临时扩容消费者。每5分钟扫描死信队列。发现10条以上同类型死信→ 查看消息体分析。临时故障→ 延迟重试。数据错误→ 自动修复后重新投递。业务异常→ 转入人工处理队列附分析报告。七、踩坑记录坑1消息确认和重试的死循环。 消费者处理失败抛异常 → Spring默认重新投递 → 再次失败 → 无限循环。必须在消费者端加重试上限javaRabbitListener(queues “order.queue”)public void handleOrder(OrderMessage order, Message message, Channel channel) {try {processOrder(order);channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);} catch (Exception e) {int retryCount getRetryCount(message);if (retryCount 3) {channel.basicNack(message.getMessageProperties().getDeliveryTag(),false, false); // 不重新入队} else {channel.basicNack(message.getMessageProperties().getDeliveryTag(),false, true);}}}坑2死信队列无限增长。 消费者挂了一晚上第二天几十万条死信。一次性清理卡死RabbitMQ必须分批javaint batchSize 1000;int totalPurged 0;while (true) {int purged rabbitAdmin.purgeQueue(“dead.letter.queue”, false);if (purged 0) break;totalPurged purged;Thread.sleep(500);}坑3测试消息泛滥。 Agent每30秒发一次测试消息队列很快全是测试数据。只在消息数或消费者数为0时才发。八、总结这套方案把RabbitMQ从半夜报警把你叫醒变成了上班看看Agent的日报。三个关键设计智能重试区分故障类型、MCP Tool标准化运维操作、死信自动分析减少人工排查。如果你也在为消息队列运维头疼建议先把监控和死信分析这块搭起来——ROI最高的部分。有用的话点赞收藏下一篇《AI Agent Spring SecurityMCP协议实现动态权限和自动审计》。
