NOTEDevOps
从 Dubbo Connection Refused 追到容器服务与内存配置
本文结论
一次 Dubbo 消费端连接被拒绝的排查:从最深层异常确认 provider 不可用,再定位容器退出与内存上限。
应用日志不断出现 Dubbo RemotingException,最深层异常是 Connection refused。堆栈很长,前面还夹杂业务接口、代理类和重试线程,很容易让人先去检查调用参数或客户端代码。
但 Connection refused 的含义非常具体:目标地址可以路由到,TCP 连接却被立即拒绝。通常是目标端口没有进程监听,或容器刚好停止。它与请求超时、DNS 失败和业务异常不是同一类问题。
沿最深层异常向外验证
排查顺序从网络事实开始:
- 消费端最终尝试连接哪个 host 和 port;
- 对应端口是否存在监听;
- 服务容器是否正在运行、重启或已经退出;
- 注册中心是否还保留着失效 provider;
- 容器最近一次退出原因和日志尾部是什么。
检查显示 provider 容器并不稳定。它退出后,消费者仍然持有之前发布的地址,于是定时重连持续产生 Connection refused。Dubbo 只是最先暴露症状的组件。
容器为什么退出
容器状态和运行记录进一步指向内存压力。Java 服务的堆设置、容器内存限制和主机可用内存不匹配,进程在负载上升时被终止。只重启容器会短暂恢复端口,但没有消除再次退出的条件。
修复需要同时考虑两个边界:
- JVM 最大堆不能逼近容器总内存上限,还要给 metaspace、线程栈、直接内存和系统库留空间;
- Compose 或编排平台中的内存限制必须真实应用到重建后的容器,仅编辑配置但不重建不会改变当前实例。
调整后采用强制重建,而不是只执行普通 restart。镜像内容没有变化时无需盲目重新拉取镜像,重点是让新的资源配置进入容器。
验证修复是否完整
验证不止是“容器显示 running”:
- provider 端口恢复监听;
- Dubbo 消费端能重新建立连接;
- 注册中心中的实例状态与真实容器一致;
- Java 进程在一段持续负载下没有再次被 OOM 终止;
- 页面和接口恢复,且日志不再持续刷连接拒绝。
这次问题说明,RPC 异常常常只是下游运行状态的表面症状。看到 Connection refused 时,应先证明服务是否存在,再追容器为什么消失。把最深层传输错误、端口、容器退出原因和资源限制串起来,通常比在业务代码中继续寻找异常更快。
遇到类似系统问题?
先说明系统,再说明症状
如果需要生产排障、DevOps 交付或物流系统集成协作,请提供当前表现、预期结果、受影响环境、可用日志或数据样例,以及发布限制。我会从现有证据开始判断。
通过邮件开始