Ubuntu环境下NestJs/RabbitMQ无法发布消息问题排查
RabbitMQ消息无法投递问题排查
问题描述
在Ubuntu机器上,无法通过路由键向Docker容器运行的RabbitMQ服务器的交换机发布消息,甚至直接向队列发布消息也失败。该功能昨日正常运行,今日突然失效。
NodeJS服务运行在另一个Alpine镜像容器中,可正常连接RabbitMQ,能创建所需的交换机、绑定关系和队列,认证无问题(修改用户名会触发认证错误)。在RabbitMQ管理控制台创建了名为all的队列,绑定路由键#以接收所有消息,但测试脚本发布的消息始终无法投递到该队列,管理控制台也看不到消息流转痕迹。RabbitMQ日志仅显示用户test认证通过,无任何错误或警告。
RabbitMQ Docker Compose配置
rabbitmq: image: docker.io/bitnami/rabbitmq:3.11.23 ports: - '4369:4369' - '5551:5551' - '5552:5552' - '5672:5672' - '25672:25672' - '15672:15672' environment: RABBITMQ_SECURE_PASSWORD: no RABBITMQ_LOGS: /bitnami/rabbitmq/mnesia/logs RABBITMQ_PLUGINS: rabbitmq_management RABBITMQ_USERNAME: ${BROKER_USER} RABBITMQ_PASSWORD: ${BROKER_PASSWORD} TZ: Europe/Amsterdam volumes: - 'rabbitmq_data:/bitnami/rabbitmq/mnesia' expose: - 4369 - 5551 - 5552 - 5672 - 25672 - 15672 networks: - broker healthcheck: test: ["CMD", "curl", "-f", "http://localhost:15672"] interval: 5s timeout: 5s retries: 10 restart: always
NodeJS测试脚本
const amqp = require('amqplib'); const message = { message: 'world', }; async function connectAndPublish() { try { // Connect to RabbitMQ server const connection = await amqp.connect('amqp://test:test@rabbitmq:5672/'); const channel = await connection.createChannel(); // Declare exchange const exchangeName = 'the-exchange'; await channel.assertExchange(exchangeName, 'topic', { durable: true }); // Convert message to JSON and publish to the exchange const messageBuffer = Buffer.from(JSON.stringify(message)); channel.publish(exchangeName, 'hello', messageBuffer); console.log(`Message published to exchange ${exchangeName}:`, message); // Close connection await channel.close(); await connection.close(); } catch (error) { console.error('Error:', error.message); } } // Call the function to connect and publish connectAndPublish();
已尝试的操作
- 升级/降级RabbitMQ服务器版本(3.11或3.12)
- 直接向
all队列发布消息,而非通过交换机和路由键 - 重启Docker容器
可能的原因及解决方案
1. 交换机与队列绑定关系异常
检查管理控制台中the-exchange的绑定列表,确认:
- 绑定的队列确实是
all - 绑定的路由键是
#,且交换机名称与脚本中的the-exchange完全一致(RabbitMQ名称区分大小写) - 绑定操作已成功保存,未因数据异常丢失
2. 消息发布后过早关闭连接
channel.publish是异步操作,脚本中发布后立即关闭通道和连接,可能导致消息还未完成投递就被中断。修改脚本添加确认逻辑:
async function connectAndPublish() { try { const connection = await amqp.connect('amqp://test:test@rabbitmq:5672/'); const channel = await connection.createChannel(); const exchangeName = 'the-exchange'; await channel.assertExchange(exchangeName, 'topic', { durable: true }); // 开启确认模式 await channel.confirmSelect(); const messageBuffer = Buffer.from(JSON.stringify(message)); // 等待消息发布确认 await new Promise((resolve, reject) => { channel.publish(exchangeName, 'hello', messageBuffer, (err) => { if (err) reject(new Error(`Publish failed: ${err.message}`)); else resolve(); }); }); console.log(`Message published to exchange ${exchangeName}:`, message); await channel.close(); await connection.close(); } catch (error) { console.error('Error:', error.message); } }
3. 用户权限不足
test用户可能缺少对应权限:
- 进入管理控制台→用户→
test→权限,确认其对默认虚拟主机/拥有configure、write、read权限 - 尝试使用docker-compose中配置的
${BROKER_USER}用户测试,排除权限问题
4. RabbitMQ持久化数据损坏
持久化卷rabbitmq_data中的元数据(队列、绑定关系)可能损坏:
- 停止RabbitMQ容器,备份
rabbitmq_data卷数据 - 删除该卷,重新启动RabbitMQ容器,重建队列和绑定关系后测试
5. 网络数据包丢失(极端情况)
虽然能连接,但可能存在底层网络问题:
- 确认NodeJS容器和RabbitMQ容器在同一个
broker网络中 - 在NodeJS容器内执行
nc -zv rabbitmq 5672测试端口连通性 - 查看Docker网络日志,排查是否有数据包丢弃情况
内容的提问来源于stack exchange,提问作者Postie
相关产品推荐
相关产品推荐

