github.com/hashicorp/consul/api 是官方 Go SDK,需显式配置地址、Token(ACL启用时)、健康检查(含DeregisterCriticalServiceAfter)及PassingOnly查询,避免panic和脏数据。

引入 github.com/hashicorp/consul/api 并初始化 client
直接用官方 SDK 最可控,不依赖框架抽象层。别用过时的 micro/go-plugins/registry/consul(v2 已移除),也别套用 Spring Cloud Consul 那套注解风格——Gin 本身没自动注册能力,得自己写注册逻辑。
关键点:
-
api.DefaultConfig()返回的默认配置只连本地127.0.0.1:8500,必须显式改cfg.Address - Consul agent 地址填错会导致
client.Agent().ServicesWithFilter直接 panic,不是返回 error;建议加time.AfterFunc(2*time.Second, ...)延迟初始化,避免启动时 Consul 还没 ready - 若 Consul 启用了 ACL,需在
cfg.Token赋值,否则所有写操作(如注册服务)都会返回Unexpected response code: 403
服务注册必须带 Check 字段,否则状态为 critical
只调 client.Agent().ServiceRegister(&api.AgentServiceRegistration{...}) 是不够的。Consul 默认不会给服务加健康检查,注册后实例会立刻被标为 critical,下游查不到它。
正确做法是显式传入 Checks 切片:
checks := []*api.AgentServiceCheck{
{
HTTP: fmt.Sprintf("http://%s:%d/health", host, port),
Timeout: "5s",
Interval: "10s",
DeregisterCriticalServiceAfter: "30s",
},
}
注意:
-
DeregisterCriticalServiceAfter是保命参数:服务挂了且连续 30 秒没上报健康,Consul 才真正剔除它;设太短容易误删,设太长导致故障实例残留 - HTTP 检查路径必须真实返回 200,Gin 路由里得加
GET /health,内容可简单写c.String(200, "ok") - 别用
TCP检查——gRPC 服务端口对 HTTP client 不通,会误判下线
客户端查询要加 PassingOnly: true 参数
调 client.Health().Service(name, "", false, nil) 默认返回所有状态的服务实例,包括 critical 和 warning 的脏数据。生产环境必须加过滤:
result, _, err := client.Health().Service(
usersrvinfo.Name,
"",
true, // ← 这个 true 就是 PassingOnly
&api.QueryOptions{AllowStale: false},
)
常见错误:
- 漏掉第三个参数,结果拿到已崩溃但未 deregister 的实例地址,
grpc.Dial直接连失败 -
AllowStale: true在高并发场景下可能读到旧缓存,Consul 集群节点多时尤其明显;除非明确接受最终一致性,否则保持false - 没处理
result为空切片的情况,直接取result[0]panic
Consul DNS 方式在容器里基本不可用
看到文档说能用 user-service.service.consul 做服务发现?别信。Docker 或 Kubernetes 里默认 net.LookupHost 查不到这个域名,因为:
- Consul DNS 接口监听的是
8600端口,不是标准53,需额外配dnsmasq或consul-template转发 - K8s Pod 的
/etc/resolv.conf不含 Consul DNS server,dig user-service.service.consul必然超时 - Gin 启动时若依赖 DNS 解析,会卡住或 fallback 到 localhost,导致调用失败
真要用 DNS 方式,必须在容器启动前注入 nameserver 127.0.0.1 并运行 dnsmasq,成本远高于直接走 HTTP API。实际项目中,99% 都走 client.Health().Service 拉列表 + 本地缓存兜底。


















