consulapi.newclient()初始化必须显式设address(带协议,如"http://consul:8500")和timeout(建议3*time.second),否则90%因连错地址或goroutine卡死导致失败;服务注册须配健康检查且id唯一,发现必须用health().service()并传passingonly:true。

consulapi.NewClient() 初始化必须设 Address 和 Timeout
连不上 Consul,八成是因为 consulapi.NewClient() 没配 Address 或超时。默认地址是 "http://127.0.0.1:8500",但 Docker 里通常是 "http://consul:8500",K8s 中得写成 "http://consul.default.svc.cluster.local:8500";漏掉协议(比如只写 "consul:8500")会直接报错。
Timeout 更隐蔽:默认为 0(无限等待),DNS 解析慢或 Consul 卡顿就会卡死 goroutine,导致服务起不来。建议固定设为 3 * time.Second。
-
Address必须带协议,"http://"或"https://"不可省 - ACL 开启时,
Token字段要传;没开 ACL 就别传,否则可能触发403 Forbidden - 别在
init()里全局复用 client 实例——不同服务实例应按生命周期各自创建
ServiceRegister() 必须带健康检查且 Check.HTTP/Check.TTL 要配对
只调 client.Agent().ServiceRegister(),服务注册成功了,但 Consul 会把它标为 critical 状态,Health().Service() 查不到它,下游根本发现不了——等于白注册。
HTTP 类型检查最常用,但 Check.HTTP 地址必须能让 Consul Server 主动访问到,不能填 "http://localhost:8080/health";真实地址应类似 "http://10.244.1.5:8080/health"。TTL 模式更可控,但必须配套心跳续期,且续租路径是 "service:<id>"</id>,不是 "service:<name>"</name>。
-
Interval和Timeout别设太激进,"10s"/"1s"是线上较稳的组合 -
Check.TTL设为"15s",则心跳间隔必须 ≤ 15s,且需另起 goroutine 定期调client.Agent().UpdateTTL() - 续租失败时别 panic,应降级走本地缓存,并记录 warn 日志
服务发现必须用 Health().Service() 并传 passingOnly=true
client.Agent().Services() 返回的是本机注册的服务列表,对服务发现完全没用;client.Catalog().Services() 只返回服务名,不含节点、地址、健康状态,也不能用于负载均衡。
真正要用的是 client.Health().Service(),它返回通过健康检查的实例集合。漏掉 passingOnly=true 参数,你拿到的可能是已宕机但还没被踢出的“僵尸实例”——下游请求直接 503。
- 调用格式是
client.Health().Service("order-service", "", true, &consulapi.QueryOptions{}) - 返回结果中
Service.Address和Service.Port才是下游可直连的真实地址,别再硬编码 - 需要按 tag 过滤时,第三个参数填字符串如
"v1,primary",不是切片
进程退出前必须显式调用 ServiceDeregister()
Consul 不会自动清理宕机服务——它靠健康检查被动剔除,但这个过程有延迟(至少一个检查周期)。如果进程优雅退出时不主动注销,Consul 里会残留一条“假在线”记录,下游可能持续往已下线实例发请求。
注册时用的 ID 必须和注销时一致,且注销动作应在 os.Interrupt 或 syscall.SIGTERM 信号处理中同步执行,别依赖 defer(可能来不及跑完)。
- 注销前加日志,方便确认是否执行成功
- 注销失败不阻塞退出,但需 warn 记录,避免误判服务已清理
- 若使用 TTL 健康检查,注销后仍建议等一个 TTL 周期再彻底关闭,防止 Consul 状态未及时同步
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











