电脑知识铺
第二套高阶模板 · 更大气的阅读体验

服务发现常见问题解析:端口映射中的坑你踩过几个?

发布时间:2025-12-30 20:30:33 阅读:97 次

服务注册了却访问不到?先查端口映射

你在本地跑了个微服务,注册到 Consul 或 Eureka 上,结果其他服务调用时报错连接超时。第一反应可能是注册中心出问题了,但更多时候是端口映射没配对。

比如你在 Docker 里启动了一个服务,容器内部监听的是 8080 端口,但宿主机没做端口映射,外部自然访问不了。这时候服务虽然在注册中心显示健康,但实际请求根本到不了。

docker run -d -p 8081:8080 my-web-service

上面这行命令把容器的 8080 映射到宿主机的 8081。如果只写了 -p 8080:8080,而注册中心上报的是宿主机 IP + 8081,那其他服务按这个地址去连,必然失败。

动态端口分配导致服务发现混乱

有些场景下,为了防止端口冲突,会使用随机端口启动服务,比如 Spring Boot 设置 server.port=0。服务启动后随机选一个可用端口,再自动注册到发现中心。

问题来了:如果没正确获取到实际绑定的端口并上报,注册中心存的就是错的地址。别人按这个连,连不上很正常。

解决办法是在服务启动后,从环境变量或运行时接口读取真实端口,再注册。Kubernetes 中一般由 kube-proxy 处理,但自建集群就得自己小心。

内网 IP 被注册出去,外部服务无法访问

机器在内网,启动时自动上报了自己的局域网 IP,比如 192.168.1.100。这个地址在注册中心一存,其他跨网络的服务看到就去连,结果当然是不通。

这种情况多见于混合部署环境,比如一部分服务在云上,一部分在本地机房。正确的做法是配置服务发现客户端,上报公网 IP 或反向代理地址。

例如在 Nacos 配置中指定:

nacos.discovery.ip=47.98.123.45
nacos.discovery.port=8081

健康检查通过,但实际请求失败

注册中心定时做健康检查,只要 HTTP 返回 200 就认为服务可用。但有时候服务虽然能响应心跳,真正处理业务请求时却卡死或超时。

更麻烦的是,健康检查走的是内网地址,而外部调用可能经过 NAT 或防火墙,路径不一样。内网通不代表外网通。

建议健康检查的路径和端口跟实际对外服务保持一致,最好模拟真实调用链路。如果用了端口映射,确保检查的是映射后的端口。

DNS 缓存导致服务列表更新延迟

有些服务发现依赖 DNS 查询,比如 Consul 的 DNS 接口。操作系统或 JVM 会缓存 DNS 结果,默认可能缓很久。

一个服务挂了,DNS 已更新,但你的程序还在用旧 IP 访问,连了一堆不存在的地址。这种问题很难排查,日志里全是连接拒绝。

可以调整 JVM 的 DNS 缓存策略,在 java.security 里设置:

networkaddress.cache.ttl=30
networkaddress.cache.negative.ttl=5

这样每次 DNS 查询最多缓存 30 秒,避免长时间使用过期地址。