Consul服务状态为critical的根本原因是健康检查未通过,需在ServiceRegistration中显式配置Check字段,确保HTTP探针地址可达、超时合理、注册时机晚于HTTP Server启动。

Consul健康检查失败导致服务状态critical
服务注册后在Consul UI里一直显示critical,不是注册没成功,而是健康检查压根没通过。Kratos服务启动后若没显式配置Check字段,Consul默认就把它当“不可用”处理——哪怕进程活着、端口通着,照样踢下线。
常见错误是只写了ServiceRegister(),却漏掉api.AgentServiceRegistration{Check: ...}。必须手动构造带HTTP探针的Check:
-
HTTP地址不能写http://127.0.0.1:9000/health——Consul Server在宿主机或另一容器,根本访问不到你的回环地址;得换成同Docker网络内可解析的名,比如http://kratos-user:9000/health -
Timeout建议设为5s,且必须≤你的/health接口P95耗时+网络毛刺余量;若DB连接池卡住导致健康接口平均响应1.8s,那Timeout: "1s"就是自找麻烦 -
Interval别盲目调小,"2s"看似激进,但若后端P95是1.5s,中间再加DNS解析、TLS握手、网络排队,极易误判;推荐从"10s"起步,再按压测数据下调
Kratos服务监听地址配错导致Consul探测失败
Consul健康检查走的是HTTP请求,而你的服务如果只监听127.0.0.1:9000,那外部(包括Consul Agent)根本连不上。错误日志里常出现connection refused或timeout,但netstat -tlnp | grep 9000又显示端口占着——八成是监听地址问题。
检查Kratos HTTP Server初始化代码,确保server.NewHTTPServer()传入的host不是硬编码"127.0.0.1":
- 开发环境可用
"0.0.0.0",但生产环境建议用具体网卡IP或容器网络内可路由地址 - 在Docker Compose中,若服务名为
kratos-user,Consul Agent需能通过该名字解析到对应容器IP,否则http://kratos-user:9000/health会DNS失败 - 用
nc -zv kratos-user 9000验证端口级连通性,比ping可靠得多——ICMP通不代表TCP通
DeregisterCriticalServiceAfter设太短引发误下线
Consul发现健康检查连续失败后,并不会立刻删服务,而是等DeregisterCriticalServiceAfter超时才真正移除。这个值如果设成"30s",而你的网络偶尔抖动、GC停顿或服务刚启动时/health接口还没ready,就可能被直接踢出服务列表。
默认值"1m"已足够覆盖大多数毛刺场景,不建议改小:
- 设
"1m"意味着允许连续1分钟探测失败才下线,既防误判,又给运维留出干预窗口 - 若真有服务崩溃,1分钟延迟对故障恢复影响有限;但若因GC STW(比如G1并发标记阶段)导致短暂心跳中断,
"30s"就会雪上加霜 - 这个参数在
api.AgentServiceRegistration里传入,不是Consul Server全局配置,每个服务可单独控制
服务注册时机早于HTTP Server启动
有人把Consul注册逻辑放在init()函数或main()开头,结果服务刚注册完,HTTP Server还没Listen(),第一次健康检查就失败,直接标critical。后续即使Server起来了,Consul也不会自动重试,除非你手动触发Pass或等下次周期检查。
正确做法是等HTTP Server真正运行起来后再注册:
- 在
server.NewHTTPServer().Start()返回后,再执行Consul注册逻辑 - 或者用channel同步:启动Server的goroutine发一个
done信号,注册逻辑select等待该信号 - Kratos 2.8.2已修正Watch Resolver goroutine相关问题,但注册时机仍需业务层自己把控
/health端点不可达、响应慢、监听地址不对,或注册太早,它就给你打critical——这个状态不会自动恢复,必须人工干预或等DeregisterCriticalServiceAfter触发清理。


















