Go 服务注册 Nacos 的坑与解决方案——从 404 到连接成功的排查之路
前言
在微服务架构中,Nacos 作为注册中心和配置中心,承担着服务注册与发现的重要职责。最近在项目中遇到了一个问题:我有一个 Go 服务想要被 Java 服务通过 RestTemplate
调用,但一开始总是报 404 或连接失败。经过排查,才发现问题出在 服务注册的 IP 配置 上。本文记录整个排查过程和解决方案,希望对大家有帮助。
问题现象
- Go 服务启动后注册到 Nacos,服务名为
go-service
。 - Java 服务调用 Go 服务:
restTemplate.getForObject("http://go-service/api/xx", String::class.java)
- 出现以下错误:
- 最开始:
No servers available for service: 192.168.1.100
- 修改 IP 后:
Connection refused: connect
- 直接用 Java 调用本地 Go IP+端口绕过服务发现可以成功
排查步骤
1. 检查 Nacos 控制台的实例信息
- 发现 Go 服务注册的 IP 是
127.0.0.1
或 Nacos 的 IP192.168.1.100
,端口也不正确。 - 这是根本原因:Nacos 记录的是 “服务实例在哪儿”,IP/Port 必须是服务实际监听的地址。
2. 确认 Go 服务监听端口
func StartHttpServer() {log.Println("HTTP 服务监听于 :8000")mux := http.NewServeMux()RegisterRoutes(mux)if err := http.ListenAndServe(":8000", corsMiddleware(mux)); err != nil {log.Fatal("HTTP 启动失败:", err)}
}
- Go 服务监听在
:8000
,确保对外可访问(生产环境不要用127.0.0.1
,应使用局域网 IP)。
3. 修正 RegisterInstanceParam 配置
param := vo.RegisterInstanceParam{Ip: "192.168.1.100", // Go 服务真实 IPPort: 8000, // 与 ListenAndServe 保持一致ServiceName: "go-worldtech",GroupName: "DEFAULT_GROUP",Ephemeral: true,
}
success, err := namingClient.RegisterInstance(param)
- IP 必须是服务实际可访问的地址,而不是 Nacos 的地址。
- Port 必须是服务监听端口。
4. 验证
- Java 调用:
restTemplate.getForObject("http://go-worldtech/api/xx", String::class.java)
- 成功返回,问题解决。
原理总结
1. 服务注册
-
服务启动时,向 Nacos 注册:
- ServiceName:服务名称
- IP + Port:服务实例可访问地址
- 健康状态、权重、分组等信息
-
Nacos 保存实例列表,用于服务发现和负载均衡。
2. 服务发现
- Java 服务通过服务名请求 Nacos,获取所有健康实例列表。
- 负载均衡器从实例列表中选择一个进行实际调用。
- 如果 IP 或 Port 配置错误,客户端会访问不到服务。
3. 健康检查与负载均衡
- 临时实例需要心跳,断线自动下线。
- 负载均衡(如 Spring Cloud LoadBalancer)根据权重选择实例。
注意事项
-
注册 IP/Port 必须是服务可访问地址
- 本机测试可以用
127.0.0.1
。 - 跨机调用必须用局域网 IP 或外网 IP。
- 本机测试可以用
-
端口必须和服务监听端口一致
-
Group / Cluster
- Java 端默认拉
DEFAULT_GROUP
,注册时不要乱写。
- Java 端默认拉
-
临时 vs 永久实例
- 临时实例更适合动态服务;永久实例适合静态服务。
总结
- Nacos 只是注册中心,IP/Port 要注册成服务实际可访问的地址。
- Java 的
RestTemplate + @LoadBalanced
调用流程依赖 Nacos 返回的实例列表。 - 正确的注册和健康检查,是服务发现和负载均衡能够正常工作的前提。
这次从 404 → 连接失败 → 成功的排查过程,也是理解 Nacos 注册与发现机制的最佳实战案例。