Appearance
Readiness、Liveness、Startup Probe 怎么分工
很多 Kubernetes 服务“不稳定”,问题并不在镜像,也不在调度,而是在探针设计上。
最常见的现象包括:
- Pod 明明起来了,但一接流量就报错
- 应用启动慢,被反复重启,永远起不来
- 短暂依赖抖动导致实例被频繁杀掉
- 服务发布时明明副本够,线上还是出现请求尖峰失败
这些问题大多和这三个探针分工不清有关:
Readiness ProbeLiveness ProbeStartup Probe
先说结论
Readiness负责回答“现在能不能接流量”Liveness负责回答“这个进程是不是已经卡死,需要被重启”Startup负责回答“应用是不是还在正常启动阶段,先别急着按存活探针处理”
最容易犯的错误不是不会配置,而是让一个探针同时承担多个职责。这样一来,流量切换、故障自愈和启动保护就会互相打架。
一、为什么探针不是“配上就行”
探针的本质不是做健康检查展示页,而是参与平台决策:
- 是否把流量转进来
- 是否把实例从 Service 里摘掉
- 是否要重启这个容器
- 是否认为启动已经超时
也就是说,你返回的每一个成功或失败,都会直接影响线上调度行为。
所以探针设计错了,后果往往不是“监控页不准”,而是:
- 正常实例被踢出流量
- 未就绪实例提前接流量
- 慢启动服务被误杀
- 短暂故障被放大成频繁重启
二、Readiness:只回答“能不能接流量”
Readiness 和可用性直接相关,但它不应该承担“判死刑”的职责。
一个实例 readiness 失败时,更合理的效果是:
- 暂时从 Service 后端摘掉
- 不再接收新流量
- 但容器本身先别急着重启
它更适合检查:
- 应用核心依赖是否基本可用
- 关键初始化是否完成
- 必要配置、线程池、连接池是否准备就绪
- 是否处于发布中的预热阶段
但要注意,readiness 不应该耦合过多外围依赖。比如某个低优先级外部接口偶发超时,不应该导致整个服务立刻从流量里摘除,否则会造成可用性被过度放大。
三、Liveness:只处理“进程活着但已经不工作”的情况
Liveness 最容易被误用。
很多团队把 /health 接口同时给 readiness 和 liveness 用,结果只要数据库连不上、Redis 短暂抖一下,Kubernetes 就开始重启容器。问题不仅没好,反而把连接风暴、缓存击穿、线程池抖动进一步放大。
Liveness 更适合判断的是:
- 进程是否死锁
- 主线程是否卡死
- 内部事件循环是否停止
- 应用是否进入无法自行恢复的坏状态
换句话说,只有在“重启比等待更有价值”的场景下,liveness 才应该失败。
四、Startup:保护慢启动服务别被误杀
很多 Java 服务、Spring Boot 服务、带大量缓存预热或数据加载的服务,启动时间本来就不短。
如果这时候直接上 liveness,容器还没来得及启动完成,就会被认为“不健康”,然后触发重启。最终出现一种很典型的现象:
- Pod 一直在启动
- 日志每次都差不多
- 但永远过不了健康检查
Startup Probe 的意义,就是告诉 Kubernetes:
- 这个应用现在还处在冷启动阶段
- 在 startup 成功前,先不要按 liveness 的标准来判断它
这对 Java、搜索、分析、消息类组件尤其重要,因为它们经常存在:
- 类加载慢
- 配置初始化多
- 本地缓存预热
- 集群元数据同步
五、三个探针更实用的分工方式
如果用一句最容易记住的话来区分:
Readiness看“能不能对外服务”Liveness看“是不是已经需要强制拉起”Startup看“是不是还在合理启动期”
一个更常见的实战组合是:
- 启动阶段由
Startup Probe兜住慢启动窗口。 - 启动完成后由
Readiness Probe控制流量接入和摘除。 - 只有在应用明显卡死或进入不可恢复状态时,才让
Liveness Probe失败并触发重启。
六、线上最容易踩的几个坑
1. 一个接口同时给三个探针用
这样最省事,但职责混乱最严重。探针触发动作不同,判断条件也不该完全一样。
2. 把所有依赖都挂进 readiness
一旦某个非核心依赖偶发抖动,整个服务都会被摘流量,反而造成可用实例数快速下降。
3. 用 liveness 处理外部依赖故障
数据库短时不可用、MQ 短时超时,并不一定意味着应用进程坏了。此时频繁重启只会加剧雪崩。
4. 没给慢启动服务配置 startup
Java 项目、老系统、初始化较重的服务特别容易因此反复重启。
5. 探针阈值照抄模板
不同服务的启动时间、依赖复杂度、请求耗时差异很大,统一模板往往在测试环境正常,一上生产就暴露问题。
七、发布和排障时怎么用探针更稳
如果目标是让服务发布更平滑、排障更清晰,更建议这样设计:
- 把应用就绪判断和进程存活判断拆开。
- 对慢启动应用单独评估 cold start 时间,配置 startup 窗口。
- 把 readiness 和预热流程结合起来,例如缓存未热完先不接流量。
- 对 liveness 保守一些,只在真正卡死或内部核心循环异常时才失败。
- 上线前专门演练三种场景:慢启动、依赖抖动、线程卡死。
八、排查探针问题时的顺序
如果线上出现“实例反复摘流量”或“不断重启”,可以先按这个顺序看:
- 是 readiness 失败还是 liveness 失败,先分清触发源。
- 失败发生在启动期还是运行期。
- 探针检查的是应用自身状态,还是某个外部依赖。
- 探针阈值是否明显不符合当前启动耗时和运行耗时。
- 发布期间是否因为预热不足导致 readiness 过早成功。
很多时候问题不是 Kubernetes 有 bug,而是探针承载了本不属于它的职责。
一句话总结
探针的关键不在于配了几个字段,而在于职责边界是否清楚。Readiness 管流量,Liveness 管自愈,Startup 管慢启动保护。
把三者分工拆清后,服务发布会更平滑,异常定位会更直接,Kubernetes 也不再是“动不动就乱重启”的背锅对象。