consul服务注册需显式配置健康检查:http检查要求完整url、正确duration字符串格式;ttl检查需主动续命并设超时重试;客户端须处理缓存与熔断;进程退出前应捕获信号并同步注销。

Consul 服务注册时怎么配健康检查(HTTP 类型)
Consul 不会自动认为你注册的服务“活着”,必须显式声明健康检查方式。HTTP 检查最常用,但路径、超时、间隔稍配错,服务就立刻被标记为 critical。
-
http字段必须是完整 URL(含协议和端口),比如"http://localhost:8080/health";写成/health或localhost:8080/health都会失败,日志里只报"Failed to do HTTP request" -
interval和timeout单位都是字符串,如"5s",不能写数字5,否则注册直接被拒,错误信息是"Invalid check: timeout must be a duration string" - Go 服务若监听
127.0.0.1,Consul agent 在另一台机器上就无法访问 —— 必须绑定0.0.0.0或实际网卡 IP,否则健康检查永远超时
Go 服务自己实现心跳上报(TTL 类型检查)
TTL 检查适合不想暴露 HTTP 接口、或健康逻辑较重的场景,但依赖服务主动“续命”,漏发一次就掉线。
- 注册时设
"ttl": "30s",然后每15s左右调一次PUT /v1/agent/check/pass/{checkID},间隔建议 ≤ TTL 的 1/2,否则网络抖动容易误剔除 - Go 里用
http.Client上报时,务必设Timeout(比如5s),否则一次卡住会阻塞整个 ticker,后续心跳全断 - 不要在
main()退出前才 defer 注销检查 —— Consul 不会等你优雅下线,得提前发PUT /v1/agent/check/fail/{checkID}或直接 deregister
服务被 Consul 剔除后,客户端还在发请求?
Consul 的服务发现结果有缓存,默认 TTL 是 0(即不缓存),但很多 Go 客户端库(比如 consul-api 或自研 DNS 封装)会加本地缓存,导致已下线服务仍被轮询到。
- 确认你用的 SDK 是否开启
cache:例如consul.NewClient(&consul.Config{...})默认不缓存,但加了consul.CacheEnable就要手动控制MaxAge - 服务端剔除后,客户端首次请求可能收到
connection refused或context deadline exceeded—— 这不是 Consul 同步慢,而是你没做熔断或重试降级 - 别依赖 Consul 的
PassingOnly查询参数一劳永逸:它只过滤查询结果,不解决 DNS 缓存、连接池复用旧连接等问题
Go 程序里怎么安全地触发服务注销
进程被 SIGTERM 杀掉时,如果没来得及通知 Consul,该服务实例会在健康检查超时后才被剔除(默认 30–60 秒),期间流量照常打入已死进程。
立即学习“go语言免费学习笔记(深入)”;
- 用
signal.Notify捕获os.Interrupt和syscall.SIGTERM,在 handler 里先停 HTTP server(srv.Shutdown()),再调 Consul deregister 接口 - 注销接口本身可能失败(网络断、Consul 挂),所以得设短超时(
3s)+ 最多重试一次,别卡住退出流程 - 别把注销逻辑放在
defer——defer只在函数 return 时执行,而 main 函数收到信号后不会自动 return,得显式调os.Exit(0)










