服务注册了却访问不到?先查端口映射
你在本地跑了个微服务,注册到 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 秒,避免长时间使用过期地址。