关键是要将 retries 与 --start-period、--timeout、--interval 协同配置:retries=3 表示连续失败 3 次才判定不健康;start-period=60s 隔离启动期失败不计数;timeout=5s 留响应余量;interval=20s 平衡抖动与故障发现。

关键不是只设一个 retries 值,而是把它和 --start-period、--timeout、--interval 配合起来用,让重试真正起作用。
重试次数(retries)本身不防抖动,得靠组合逻辑
单独把 retries 设成 3 或 5 并不能解决瞬时抖动问题。Docker 的重试机制是“连续失败才计数”,但若第一次检查就在应用还没启动完时就失败了,这次失败会被计入——这就不是抖动,而是误判。所以必须配合 --start-period 把初始化阶段隔离出来。
- retries=3:表示连续 3 次失败才标为 unhealthy;设为 1 容易被单次超时打掉,设为 5 可能掩盖真实故障
- start-period=60s:容器启动后前 60 秒内的失败不计入重试计数,专治 Spring Boot、PostgreSQL 等慢启动服务
- timeout=5s:比业务平均响应时间多留 2–3 秒余量,避免高负载下正常请求被误杀
- interval=20s:太密(如 5s)会放大抖动影响,太疏(如 60s)延迟发现故障;15–30s 是 Web 类服务常用区间
健康检查命令要能区分“真失败”和“抖动”
用 curl -f 调 /health 是基础,但重点在于这个端点自身是否抗抖动:
- 避免在健康接口里查远端数据库或调第三方 API;抖动发生时,这些依赖最容易先挂,导致整个服务被连带标记为 unhealthy
- 推荐分层设计:
/ready检本地进程+端口+关键文件锁,/health再加轻量级依赖连通性(如 ping Redis) - 如果必须查外部依赖,给它单独加超时,比如
redis-cli -h redis --scan-timeout 1000 ping || exit 1
Docker Compose 中的写法示例(推荐 JSON 数组格式)
避免 shell 解析歧义,尤其含空格或管道符时:
healthcheck: test: ["CMD", "curl", "-f", "-s", "http://localhost:8080/actuator/health"] interval: 25s timeout: 4s start_period: 75s retries: 3
这里 start_period: 75s 给足初始化时间,retries: 3 允许中间出现一次网络波动,timeout: 4s 留出响应缓冲,三者协同才能把“抖动”和“真故障”区分开。
验证是否生效:看 failing streak 和状态流转
运行容器后执行:
docker inspect <容器名> | jq '.[0].State.Health'
关注两个字段:
-
Status:当前是
starting、healthy还是unhealthy -
FailingStreak:当前连续失败次数;如果它在
starting阶段一直为 0,进入healthy后偶尔跳到 1 又回落,说明重试机制正在工作
若 FailingStreak 一路涨到 3 然后卡在 unhealthy,就要检查是不是健康命令本身不稳定,或者 timeout 设得太紧。


















