Consul服务不会自动下线,是因为未配置健康检查(Check)或参数不合理;Hyperf默认仅注册元数据而不附带Check,必须显式配置HTTP/TCP/TTL检查及deregister_critical_service_after等参数才能触发自动剔除。

Consul 服务不会自动下线,是因为你没配健康检查(Check)或配了但超时参数不合理 —— 默认不注册 Check,Consul 就当服务永远健康。
为什么 Consul 不自动下线挂掉的服务
Hyperf 默认只调用 ConsulClient::register() 注册服务元数据,但不附带任何健康检查逻辑。Consul 收到注册后,会把该实例标记为 passing 状态并长期保留,哪怕进程已崩溃、端口已不可达。
必须显式配置 Check 才能触发自动剔除,否则 Consul 无法感知服务死亡。
- 没配 Check:服务 crash 后仍显示“healthy”,消费者持续路由过去,请求全部失败
- 配了 Check 但
timeout或interval过长:比如设成 30s 检查一次、超时 10s,那最多要等 40 秒才下线 - Check 路径返回 5xx 或超时:Consul 会先标记为
critical,连续失败若干次(默认 1 次)后才置为failed并从服务列表剔除
如何在 Hyperf 中正确配置 Consul 健康检查
关键不是“加个 check”,而是让 Check 的行为和你的服务实际存活能力对齐。Hyperf 的 hyperf/consul 扩展支持 HTTP、TCP、TTL 三种 Check 类型,推荐用 HTTP。
在 config/autoload/services.php 中补全 check 配置:
'check' => [
'http' => 'http://127.0.0.1:9501/health', // 必须是服务自身暴露的健康接口
'interval' => '5s', // Consul 每隔 5 秒发起一次 GET
'timeout' => '3s', // 单次请求超过 3 秒未响应即判失败
'deregister_critical_service_after' => '30s', // 进入 critical 状态后,30 秒内未恢复则强制下线
],
-
http地址必须可被 Consul Server 访问(注意容器网络、防火墙),不能写localhost或127.0.0.1(除非 Consul 和服务同宿主机) -
interval和timeout要满足:timeout < interval,否则连续超时会堆积,触发误下线 -
deregister_critical_service_after是真正决定“多久下线”的核心参数,不设或设太大(如24h)等于没开自动下线
常见踩坑点:Check 配了但还是不下线
即使写了上面的配置,仍可能卡在 critical 不动 —— 这通常不是 Consul 问题,而是你的服务或网络层挡住了健康探测。
- 服务没实现
/health接口,或返回非 200(比如 404、500、超时):Consul 会立即标记critical,但不会立刻 deregister - Consul Agent 无法访问服务 IP/端口:常见于 Docker 网络模式为
bridge时,Agent 在 host 网络,服务在 bridge 网络,http://127.0.0.1:9501对 Agent 来说是错的 - 服务启用了 HTTPS 但 Check 写的是 HTTP:Consul 默认不校验证书,但连接会被拒绝,表现为 timeout
- Hyperf 启动时
/health接口还没 ready(比如数据库连不上),导致首次 Check 失败,后续即使恢复也卡在critical—— 需配合initial_status设为passing或加启动等待逻辑
要不要加自定义心跳重注册?
Consul 官方机制本身不支持“断网恢复后自动重注册”。如果服务因临时网络抖动被踢出,重启前它就是不可发现的。这不是配置问题,而是 Consul 的设计约束。
如果你的场景要求高可用容灾,得额外引入类似 consul-retry-starter 这类组件,在检测到注册丢失时主动调用 register() 补注册。但这属于增强逻辑,不在标准 hyperf/consul 范围内。
真正容易被忽略的,是 deregister_critical_service_after 这个参数 —— 它不写,或者写成 0s(无效值),服务就永远不会从 Consul 列表里消失。


















