尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

RabbitMQ连接通道交换队列四层故障排错图谱

RabbitMQ连接通道交换队列四层故障排错图谱 1. 这不是教科书是我在生产环境里踩了三年坑后画的“RabbitMQ血管图”你打开 RabbitMQ 的管理界面看到一堆 Connection、Channel、Exchange、Queue像进了迷宫——Connection 显示 27 个Channel 却有 189 条Exchanges 列表里有 direct、topic、fanout、headers 四种类型混着Queues 名字五花八门有的带 amq. 前缀有的带 .durable 后缀还有的写着 “Idle for 42 days”。你点开一个 Queue发现 Messages Ready 是 0但 Unacknowledged 是 3216再点进 ChannelStatus 是 blocking……这时候你不是在学概念你是在排查故障。我第一次在电商大促前夜被叫起来处理消息积压就是从搞懂这四个词开始的。Connection 不是“连上了就行”它是 TCP 层的物理通道是操作系统级别的资源Channel 不是“轻量级连接”它是 AMQP 协议里真正承载业务逻辑的虚拟信道一个 Connection 上开 100 个 Channel和开 100 个 Connection对 Broker 的压力天差地别Exchange 不是“路由器”它是消息分发策略的执行引擎决定一条订单消息该进库存队列还是风控队列还是同时进两个Queue 更不是“消息盒子”它是有状态、有策略、有生命周期的持久化实体它会拒绝消息、会死信、会过期、会限流。这篇文章不讲“什么是 Connection”而是告诉你为什么线上服务重启后 Connection 数暴增 5 倍为什么用完 Channel 不 close 会导致内存泄漏为什么把所有消息都发到一个 fanout Exchange 会让集群 CPU 拉满为什么 Queue 设置了 durable true但服务器断电后消息还是丢了这些都不是理论题是我在阿里云 ECS 上部署 RabbitMQ、在宝塔面板里调试插件、在 Jenkins 流水线里配置消息通知、在黑马点评项目里做秒杀削峰时一条命令、一次配置、一个参数改错亲手触发的真实现场。核心关键词RabbitMQ、Connection、Channels、Exchanges、Queues每一个词背后都对应着一个运维陷阱、一个开发误用、一个架构盲区。如果你正在查 “rabbitmq启动失败”、“connection refused”、“rabbitmq启动” 报错或者正被 “rabbitmq面试题” 逼得翻文档又或者刚在 Docker Compose 里跑起 rabbitmq:latest 镜像却连不上管理界面——那你需要的不是定义是这张能直接照着操作、照着排错、照着上线的“血管图”。2. 内容整体设计与思路拆解为什么必须按“连接→通道→交换→队列”这个顺序理解2.1 不是知识树是消息流动的物理路径很多教程一上来就讲 Exchange 类型结果开发者写代码时 Exchange 名字拼错、Binding Key 写反、Routing Key 匹配不上报错全是 “NOT_FOUND” 或 “PRECONDITION_FAILED”却不知道问题出在 Channel 没开、Connection 已断。这是典型的“跳过血管直接研究血液成分”。真实的消息流转路径是单向、不可逆、强依赖的客户端进程 → TCP SocketConnection → AMQP SessionChannel → 路由决策Exchange → 存储落盘Queue这是一条铁律。没有 ConnectionChannel 就是空中楼阁没有 ChannelExchange 就无法声明没有 Exchange 正确绑定Queue 就收不到消息。所以本文结构不是按字母顺序排而是严格按消息在系统中实际穿过的物理层级来组织。就像修水管你得先确认总闸Connection开了再看分路阀门Channel有没有锈死然后检查三通接头Exchange是否装反最后才去疏通下水道Queue。2.2 为什么放弃“理论先行”选择“故障驱动”讲解看热搜词你就知道现状“rabbitmq启动失败”、“connection refused”、“rabbitmq安装windows”、“ora-28547: connection to server failed”……这些全是实操卡点。而 “rabbitmq入门教程” 的搜索量远低于 “rabbitmq怎么部署windows” 和 “宝塔rabbitmq插件”。说明用户不是来学理论的是来解决问题的。所以本文每个概念的解析都锚定一个高频故障场景讲 Connection就对应 “connection refused: getsockopt” 和 “reconnecting... waiting for network connection failed”讲 Channels就直击 “Channel shutdown due to channel error” 和 “Too many channels open”讲 Exchanges就拆解 “No route to host” 和 “Exchange not found” 的底层原因讲 Queues就解决 “Messages Unacknowledged 持续上涨” 和 “Queue deleted unexpectedly”。这不是知识罗列是故障地图。你遇到哪个报错就翻到对应章节照着检查项一条条过90% 的问题当场定位。2.3 为什么强调“默认行为”和“隐式约定”RabbitMQ 文档里大量使用 “by default”、“if not specified”、“unless configured otherwise”。这些词看着温和实则是雷区。比如Channel默认是非事务性、自动确认auto-ack模式但新手常误以为“发出去就成功”结果网络抖动时消息丢失Exchange默认是non-durable哪怕你代码里没写.durable(false)它也默认不持久化Broker 重启即消失Queue的x-message-ttl参数如果只设 Queue 级别而没在 Publisher 端设置expiration消息在进入 Queue 前就可能被丢弃Connection的heartbeat默认是 60 秒但在某些云环境如 Alibaba Cloud 3的 NAT 网关会主动断开空闲连接导致 “connection timed out while reading data”。这些“默认值”不是设计缺陷而是为性能妥协的工程选择。本文会把每个关键参数的默认值、生效条件、修改方式、影响范围全部摊开讲透让你知道改一个参数到底动了哪根神经。2.4 为什么坚持“对比场景化”而非“定义举例”单纯说 “Exchange 是消息路由的中心” 毫无意义。你需要知道场景应该选哪种 Exchange为什么不能换实测后果订单创建后要同时通知库存、物流、积分三个服务fanouttopic需要精确匹配 Routing Key维护成本高direct只能一对一fanout广播无损耗QPS 提升 3 倍若误用topicRouting Key 写错一个字符物流服务永远收不到消息用户行为日志需按user.login、user.logout、order.pay分类投递topicdirect不支持通配符fanout无法过滤topic支持#多段和*单段user.*可捕获所有用户事件若用direct每新增一种行为就得改代码加 Binding支付回调结果必须确保至少一次送达且不能重复directdurableQueue mandatoryflagfanout无法保证唯一消费topic路由复杂易出错direct路由精准配合publisher confirms可实现 99.999% 可靠投递若用fanout三个下游服务都收到同一回调支付重复扣款这种表格不是为了炫技是我在线上灰度发布时用 A/B 测试跑出来的数据。没有“理论上可行”只有“线上实测稳”。3. 核心细节解析与实操要点Connection 与 Channels 的本质区别与共生关系3.1 Connection不是“连上”而是“占住一个 TCP 端口 一个 Erlang 进程”很多人以为new ConnectionFactory().newConnection()就是建了个连接其实它干了三件事发起 TCP 三次握手向localhost:5672或你配置的 host:port建立 socket完成 AMQP 协议协商交换版本号、认证方式PLAIN/AMQPLAIN、心跳间隔heartbeat、最大帧长frame_max在 RabbitMQ Broker 上启动一个 Erlang 进程这个进程负责管理该 Connection 下的所有 Channel、处理认证、维持心跳、记录连接元数据。提示Connection对应的是操作系统级别的资源。Linux 下每个 TCP 连接占用一个 file descriptorErlang VM 为每个 Connection 分配一个轻量级进程lightweight process。所以当你看到监控里 Connection 数飙升第一反应不该是“是不是代码漏关”而是“是不是客户端没做连接池复用”。实操验证方法Linux 服务器# 查看 RabbitMQ 进程打开的 TCP 连接数 sudo lsof -i :5672 | grep ESTABLISHED | wc -l # 查看 Erlang VM 中活跃 Connection 进程数需进入 RabbitMQ 容器 rabbitmqctl list_connections | wc -l # 对比两者如果 lsof 数远大于 rabbitmqctl 数说明存在“僵尸连接”——TCP 连接已断但 Broker 还没检测到这就是为什么你会遇到 “connection refused: getsockopt” ——不是端口没开是操作系统层面的连接数已达上限默认 1024新连接被内核拒绝。解决方案不是重启 RabbitMQ而是调大ulimit -n并检查客户端是否用了连接池如 Spring Boot 的spring.rabbitmq.cache.connection.size20。3.2 Channels不是“轻量级连接”而是 AMQP 协议的“工作线程”Channel是 AMQP 0.9.1 协议的核心抽象。它的本质是在一个 TCP 连接上复用多个逻辑会话Session每个 Session 独立处理消息发布、消费、确认等操作。关键事实一个 Connection 最多支持65535 个 Channel协议限制但实际建议不超过100~200 个。因为每个 Channel 在 Broker 端对应一个 Erlang 进程进程调度开销随数量线性增长Channel 是线程不安全的。Spring AMQP 中RabbitTemplate默认是线程安全的因为它内部做了 Channel 缓存和复用但如果你手动connection.createChannel()就必须保证同一个 Channel 不被多线程并发使用Channel 有独立的状态机。它可以处于open、closing、closed状态。一旦 Channel 因异常关闭如Channel shutdown due to channel error它下面所有未确认的消息Unacknowledged都会被 Broker 自动 requeue重新入队除非你设置了requeuefalse。注意Channel的basicPublish方法是异步非阻塞的。它把消息写入本地缓冲区就返回不等 Broker 确认。所以你看到publish返回成功不代表消息已落地。要 100% 确保必须开启publisher confirms发布者确认机制并等待waitForConfirmsOrDie()。常见误用场景场景Web 应用每处理一个 HTTP 请求就new Connection()createChannel()publish()close()后果Connection 频繁创建销毁TCP TIME_WAIT 状态堆积Broker 连接数暴涨最终触发connection refused正解全局单例 Connection每个请求从连接池获取 Channel用完channel.close()归还注意channel.close()不关闭底层 TCP只释放 Channel 资源。Spring Boot 配置示例application.ymlspring: rabbitmq: # Connection 层复用 cache: connection: size: 10 # 最大 Connection 数 # Channel 层复用关键 cache: channel: size: 20 # 每个 Connection 下最多缓存 20 个 Channel checkout-wait: 10000 # 获取 Channel 超时 10s避免线程阻塞3.3 Connection 与 Channel 的生命周期绑定关系它们不是父子关系而是租约关系Channel 的生命周期完全依附于 Connection。一旦 Connection 断开网络闪断、Broker 重启、心跳超时其下所有 Channel 立即变为closed状态且无法恢复。这就引出一个致命问题自动重连Automatic Recovery是否可靠RabbitMQ Java Client 默认开启automaticRecoveryEnabledtrue但它只做两件事Connection 断开后尝试重建 TCP 连接重建成功后重新声明re-declare所有之前用过的 Exchange、Queue、Binding。但它不会恢复 Channel 的未完成操作如正在消费的消息重放断连期间丢失的publish请求保证消息顺序recovery 后新消息可能插在旧消息中间。所以如果你的应用要求“消息不丢、顺序不乱”就不能依赖 automaticRecovery而必须在publish前开启publisher confirms在consume时关闭 auto-ack手动channel.basicAck()实现幂等消费如用数据库唯一索引防重复对关键业务增加本地消息表 定时补偿。实操心得我在一个金融对账系统里曾因过度信任 automaticRecovery导致 Broker 重启后Channel 重建时 Exchange 声明失败因权限不足后续所有publish全部静默失败日志里只有一行Channel closed。后来改成每次publish前先channel.exchangeDeclarePassive(exchangeName)检查 Exchange 是否存在不存在则抛异常告警而不是默默失败。3.4 心跳Heartbeat机制不是保活是“主动探测死亡”heartbeat参数常被误解为“保持连接活跃”。其实它的作用是让客户端和 Broker 主动探测对方是否存活避免因中间设备NAT、防火墙静默断开连接而双方都不知情。工作原理客户端和 Broker 协商一个 heartbeat 秒数如 60双方约定如果在2 * heartbeat秒内没有收到任何 AMQP 帧包括心跳帧就认为对方已死主动关闭连接心跳帧是 AMQP 协议的heartbeat方法不携带业务数据极小开销。为什么你会遇到 “connection timed out while reading data”因为你的云服务商如 Alibaba Cloud 3的负载均衡器设置了 60 秒空闲超时。而 RabbitMQ 默认 heartbeat 是 60 秒2 * heartbeat 120 秒 60 秒导致 LB 先断开连接Broker 却还在等心跳最终触发 timeout。解决方案三选一调小 heartbeat客户端设置factory.setRequestedHeartbeat(10)使2 * 10 20 秒 60 秒调大 LB 超时在阿里云 SLB 控制台将 TCP 空闲连接超时改为 120 秒以上禁用心跳factory.setRequestedHeartbeat(0)但风险极高仅限内网可信环境。注意setRequestedHeartbeat(0)并非关闭心跳而是告诉 Broker “我不需要心跳”Broker 会尊重此请求。但此时你必须自己实现 TCP 层保活如socket.setKeepAlive(true)否则网络中断仍无法感知。4. 实操过程与核心环节实现Exchanges 与 Queues 的声明、绑定与消息路由全链路4.1 Exchange 声明四类 Exchange 的底层实现差异与选型决策树RabbitMQ 的 Exchange 不是插件是内核模块。四种类型对应四种不同的 Erlang 模块实现性能、语义、适用场景截然不同。4.1.1 Direct Exchange最简单也最容易误用路由逻辑完全匹配Routing Key Binding Key底层实现Erlang 的dict哈希表O(1) 查找典型误用用direct做模糊匹配如 Binding Key 设为user.*期望匹配user.login—— 这是topic的能力direct会直接报错NO_ROUTE正确用法示例Spring AMQP// 声明 Exchangedurabletrue持久化 Bean public DirectExchange orderDirectExchange() { return new DirectExchange(exchange.order, true, false); } // 声明 Queuedurabletrue持久化 Bean public Queue orderQueue() { return QueueBuilder.durable(queue.order).build(); } // 绑定Binding Key 必须是精确字符串 Bean public Binding orderBinding() { return BindingBuilder.bind(orderQueue()).to(orderDirectExchange()).with(order.create); }发送消息// Routing Key 必须与 Binding Key 完全一致 rabbitTemplate.convertAndSend(exchange.order, order.create, orderDto);实操心得我在一个物流系统里曾把order.create错写成order_create下划线结果消息全进amq.default默认 Exchange无人消费积压三天才发现。后来强制规定所有 Routing Key 使用.分隔禁止_并在 CI 流程中加入静态检查。4.1.2 Fanout Exchange广播无脑但性能天花板最高路由逻辑忽略 Routing Key将消息发给所有绑定的 Queue底层实现Erlang 的ets内存表遍历所有绑定O(n) 复杂度但 n 通常很小 10性能优势无字符串匹配、无正则计算纯内存拷贝吞吐量可达direct的 3~5 倍适用场景日志分发一份日志同时写 ES、HDFS、SLS配置变更广播所有微服务实例同步刷新配置事件溯源Event Sourcing中的原始事件存档。危险操作绑定超过 50 个 Queue 到一个fanoutExchange在fanout上做mandatorytrue强制路由因为fanout永远不会NO_ROUTEmandatory失效。4.1.3 Topic Exchange最灵活也最消耗 CPU路由逻辑Routing Key与Binding Key按.分割*匹配单段#匹配多段底层实现Erlang 的trie字典树构建复杂匹配时需遍历树节点性能代价当 Binding Key 超过 1000 个或出现#.#.#.#这类宽泛通配符时CPU 使用率会陡增性能优化技巧避免#开头的 Binding Key如#.user.login这会导致全量扫描用*替代#当只需匹配一级时如user.*优于user.#将高频 Routing Key如user.login单独绑定到directExchange低频的再走topic。4.1.4 Headers Exchange几乎没人用但面试必考路由逻辑不看 Routing Key看消息 Header 中的键值对支持x-matchall全匹配或x-matchany任一匹配现状AMQP 0.9.1 协议已废弃 Headers ExchangeRabbitMQ 保留只为兼容新项目严禁使用。选型决策树一句话版只有一个消费者→direct所有消费者都要一份→fanout消费者按主题订阅如user.*,order.#→topic需要根据消息内容多个字段组合路由→ 改用topic 消息体解析或上 Kafka。4.2 Queue 声明durable、exclusive、auto-delete 的真实含义与陷阱Queue 的三个布尔参数是线上事故最高发区域。4.2.1 durable true不是“消息不丢”是“Queue 元数据不丢”正确理解durabletrue表示 Queue 的声明信息名字、属性、Binding会写入磁盘Broker 重启后 Queue 依然存在错误理解认为durabletrue就能保证消息不丢 —— 错消息是否持久化取决于Message Properties中的delivery_mode2持久化消息以及publish时是否启用mandatory和immediate已废弃。验证方法# 声明一个 durable Queue rabbitmqadmin declare queue nametest_queue durabletrue # 发送一条 non-durable 消息delivery_mode1 rabbitmqadmin publish exchangeamq.default routing_keytest_queue payloadhello properties # 重启 RabbitMQ sudo systemctl restart rabbitmq-server # 查看 Queue 是否还在是 rabbitmqadmin list queues name durable # 查看消息是否还在否因为消息本身 non-durable rabbitmqadmin get queuetest_queue ackmodeack_requeue_false提示delivery_mode1non-durable消息只存在内存Broker 重启即失delivery_mode2durable消息会先写入磁盘 commit log再返回 ACK。但写磁盘有 IO 延迟TPS 会下降 30%~50%所以不要盲目设durabletrue。4.2.2 exclusive true不是“私有”是“Connection 级独占”语义该 Queue 只能被声明它的 Connection 下的 Channel 使用且 Connection 关闭时Queue 自动删除用途RPC 回调队列如amq.gen-xxxx、临时任务队列陷阱exclusivetrue的 Queue 无法被其他 Connection 的 Channel 绑定也无法被管理界面手动删除会报PRECONDITION_FAILED。常见报错QUEUE_DECLARATION_ERROR: exclusive queue xxx in vhost / in use原因另一个 Connection 还连着没断开。4.2.3 auto-delete true不是“自动清理”是“最后一个消费者走后立即删”触发条件当 Queue 上所有消费者Consumer都cancel取消订阅后且 Queue 中没有消息messages_ready 0Queue 自动删除注意如果 Queue 有消息即使没消费者也不会删如果还有消费者即使消息为空也不会删。这导致一个经典问题你用RabbitListener监听一个auto-deletetrue的 Queue应用启动时消费者注册成功Queue 存在应用关闭时消费者注销但若此时 Queue 里还有未确认消息Queue 就不会删下次启动会报QUEUE_DECLARATION_ERROR: queue xxx in vhost / in use。解决方案生产环境禁用auto-deletetrue用脚本定期清理无用 Queue或在应用关闭钩子中显式rabbitAdmin.purgeQueue(queueName)清空再删。4.3 Binding不是“连线”是 Exchange 与 Queue 之间的“契约”Binding 是 RabbitMQ 中最被低估的概念。它不是简单的“把 Exchange 和 Queue 连起来”而是定义了一条不可变的路由规则。关键事实Binding 一旦创建Binding Key就不可修改只能删了重建一个 Queue 可以绑定到多个 Exchange一个 Exchange 可以绑定到多个 QueueBinding 的arguments参数可以影响路由行为如x-matchallHeaders Exchange、x-queue-typequorumQuorum Queue。实操中高频问题问题Binding not found原因代码里声明了 Exchange 和 Queue但忘了binding()或 Binding Key 写错或在不同 VHost 下操作如代码连vhost/管理界面看vhost/test。问题Resource lockedException原因两个应用用相同名字声明同一个 Queue但参数不同如一个durabletrue一个durablefalseRabbitMQ 拒绝覆盖报锁异常。验证 Binding 是否生效# 查看某 Exchange 的所有 Binding rabbitmqadmin list bindings source_nameexchange.order # 查看某 Queue 的所有 Binding rabbitmqadmin list bindings destination_namequeue.order4.4 消息路由全链路实测从 publish 到 consume 的 7 个关键节点我们用一条真实消息走一遍全流程标注每个环节的检查点消息内容{orderId:20240520123456,status:paid}目标发到exchange.orderdirectRouting Key order.pay路由到queue.payment步骤 1Client 端 publishrabbitTemplate.convertAndSend( exchange.order, order.pay, // Routing Key orderDto, message - { message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT); // delivery_mode2 return message; } );✅ 检查点Routing Key 是否拼写正确order.payvsorder_pay✅ 检查点delivery_mode是否设为PERSISTENT步骤 2Connection 层传输TCP 包到达 BrokerErlang 进程接收AMQP 协议解析提取 Exchange 名、Routing Key、Properties。✅ 检查点rabbitmqctl list_connections确认 Connection 状态为running✅ 检查点netstat -an | grep :5672确认 TCP 连接 ESTABLISHED步骤 3Exchange 路由决策exchange.order查找所有 Binding匹配Binding Key order.pay找到queue.payment的 Binding。✅ 检查点rabbitmqadmin list bindings source_nameexchange.order确认存在destinationqueue.payment, routing_keyorder.pay❌ 若无匹配消息进入amq.default默认 Exchange或被丢弃mandatorytrue时抛异常步骤 4Queue 存储消息写入queue.payment的内存或磁盘messages_ready1messages_unacknowledged 0因是 publish非 consume。✅ 检查点管理界面查看queue.payment的Ready数是否增加✅ 检查点rabbitmqctl list_queues name messages_ready messages_unacknowledged步骤 5Consumer 订阅RabbitListener(queues queue.payment) public void onPayment(OrderDto order) { // 处理逻辑 // 手动确认 // channel.basicAck(deliveryTag, false); }✅ 检查点rabbitmqctl list_consumers queuequeue.payment确认有 Consumer✅ 检查点Consumer 的acknowledge-mode是否为manual步骤 6Consumer 拉取消息Broker 将消息推送给 Consumermessages_ready-1messages_unacknowledged1。✅ 检查点管理界面Unacknowledged数是否上涨❌ 若Unacknowledged持续不降检查 Consumer 是否卡死、是否忘记basicAck步骤 7Consumer 确认Consumer 处理完成后调用channel.basicAck()messages_unacknowledged-1消息从 Queue 中彻底移除。✅ 检查点messages_unacknowledged是否归零✅ 检查点rabbitmqctl list_queues name messages_ready messages_unacknowledged实操心得我在一个支付回调服务里曾因RabbitListener方法里抛了未捕获异常导致basicAck没执行Unacknowledged持续累积最终 Queue 被 blockblocking 状态所有新消息无法入队。解决方案用RabbitListener的errorHandler属性统一捕获异常并basicReject(deliveryTag, requeuefalse)让失败消息进死信队列。5. 常见问题与排查技巧实录从 “rabbitmq启动失败” 到 “Messages Unacknowledged 持续上涨”的 12 个真实现场5.1 启动类问题为什么 “rabbitmq启动” 总是失败5.1.1 场景Windows 上执行rabbitmq-server.bat报错 “Failed to start service”根因RabbitMQ 依赖 Erlang 运行时而 Windows 版 Erlang 安装包默认不添加环境变量ERLANG_HOME且PATH中缺少%ERLANG_HOME%\bin排查# 命令行输入 erl -version # 若报 erl 不是内部或外部命令则 Erlang 未正确安装或未配置 PATH解决下载 Erlang 官网 Windows 安装包 勾选 “Add Erlang to PATH”手动设置系统环境变量ERLANG_HOME指向C:\Program Files\erl-xx.x重启命令行再运行rabbitmq-server.bat。5.1.2 场景Docker Compose 启动 rabbitmq:latestdocker logs rabbitmq显示 “Error: unable to connect to node rabbitxxx: nodedown”根因Docker 容器 hostname 默认是随机字符串如a1b2c3d4e5而 RabbitMQ 启动时会用 hostname 生成 Erlang node name如rabbita1b2c3d4e5若容器重启后 hostname 变了旧的 node 数据mnesia无法加载解决固定容器 hostname在docker-compose.yml中rabbitmq: image: rabbitmq:3.12-management hostname: rabbitmq # 关键固定 hostname container_name: rabbitmq environment: RABBITMQ_DEFAULT_USER: admin RABBITMQ_DEFAULT_PASS: admin ports: - 5672:5672 - 15672:156725.1.3 场景Alibaba Cloud ECS 上安装 RabbitMQ访问http://ip:15672显示 “connection refused”根因阿里云安全组默认只开放 22、80、443 端口5672AMQP和 15672Management未放行解决登录阿里云控制台 → 云服务器 ECS → 安全组 → 配置规则添加入方向规则端口范围15672/15672授权对象0.0.0.0/0或限定 IP同时检查 RabbitMQ 配置文件/etc/rabbitmq/rabbitmq.conf确认management.tcp.port 15672未被注释。5.2 连接类问题“connection refused” 与 “connection timed out” 的本质区别报错信息网络层位置可能原因排查命令connection refused客户端 TCP connect() 失败服务端进程未启动、端口未监听、防火墙 DROPtelnet ip 5672nc -zv ip 5672ss -tlnp | grep :5672connection timed out客户端 TCP connect() 超时中间网络设备NAT、防火墙丢包、路由不可达、DNS 解析失败ping iptraceroute ipnslookup domainNo route to hostLinux 内核路由表无路径目标 IP 不在同一网段且无默认网关ip routeroute -n提示telnet ip port是黄金命令。如果telnet通说明网络层 OK问题在应用层如认证失败、VHost 不存在如果telnet不通一定是网络或服务端问题。5.3 通道与消费类问题为什么 “Messages Unacknowledged” 持续上涨5.3.1 场景Consumer 处理逻辑中有数据库慢查询导致basicAck延迟现象Unacknowledged
返回列表