Consul agent必须本地连接,禁止直连server;Go服务注册需用context超时控制并探测leader状态,Health().Service返回空多因未配置健康检查或passingOnly参数误设,Watch需手动重连与去重。

Consul agent 必须本地连,别直连 server
Go 服务注册时 client.Address 设成 "http://10.0.1.5:8500"(远端 server IP)是常见错误。Consul 官方明确要求客户端只连本机 agent,否则会绕过本地健康检查、丢失 gossip 状态、无法触发 LAN 健康同步。
正确做法是所有 Go 服务所在机器都部署一个 consul agent(consul agent -client=0.0.0.0 -bind=真实内网IP),然后 client 地址固定为 "http://127.0.0.1:8500"。
验证方式:执行 curl http://127.0.0.1:8500/v1/status/leader 能返回 leader 地址才算通;若返回空或 connection refused,说明 agent 没起来或端口被占。
ServiceRegister 必须带 context 超时和降级逻辑
client.Agent().ServiceRegister() 默认无超时,网络抖动或 agent 启动慢时会卡住整个服务启动流程——这不是代码 bug,而是设计缺陷。
必须用 context.WithTimeout(context.Background(), 3*time.Second) 包裹调用,3 秒足够完成注册,比默认 5 秒更利于快速失败。
注册前建议加轻量探测:client.Status().Leader() 成功再注册;失败则跳过并打 ERROR 日志,服务照常启动(避免因注册中心临时不可用导致雪崩)。
别在 init() 或 main() 顶层直接 panic,生产环境要容忍注册失败——你可以 fallback 到静态地址列表或直连模式。
Health().Service 返回空?先看 passingOnly 和健康检查配置
服务明明注册成功,client.Health().Service("user-svc", "", true, nil) 却返回空列表,90% 是因为第三个参数 passingOnly 设为 true,而你根本没配健康检查。
Consul 不会自动认为注册的服务“健康”,必须显式定义:&api.AgentServiceCheck{HTTP: "http://localhost:8080/health", Timeout: "2s", Interval: "5s"}。
如果只是测试,至少写个 TTL: "30s" 并配合 Go 客户端的 client.Agent().UpdateTTL() 续租,否则实例注册后几秒就变成 critical 状态。
另外,client.Health().Service() 每次都是 HTTP 请求,别在请求处理函数里高频调用——应配合本地缓存或 client.Health().ServiceBlocking() 长轮询。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
Watch 断连后不自动重连,得自己兜底
Consul 的 watch 机制(如 client.Health().ServiceBlocking())不是长连接保活协议,网络波动或 agent 重启会导致 channel 关闭,但 goroutine 不会自动重启。
必须在外层加 for 循环检测 ok == false,并在关闭后重新调用 watch 方法;同时首次 watch 前要用 client.Health().Service() 全量拉一次,避免错过初始状态。
watch 回调里别做阻塞操作(比如同步写磁盘日志),否则响应积压会触发 stream 关闭;更新本地缓存用 sync.Map 或 atomic.Value,避免读写竞争。
最易忽略的是:watch 返回的实例列表可能含重复 IP:port,需按地址去重后再更新连接池,否则会反复新建相同连接。
立即学习“go语言免费学习笔记(深入)”;

















