qinghuan
← 回到知识探索

后端现场 / 动手实验

健康页返回 200,为什么用户还是办不了事?

把启动完成、实例还能运行和现在能否接单分开,避免把数据库故障变成所有实例一起重启。

展开本文目录
  1. 先看这一页究竟检查了什么
  2. 三个检查,分别决定不同事情
  3. 用五张状态卡拆开判断
  4. 数据库坏了,先决定还能提供什么
  5. 记住这三点
  6. 别把例子用过头
  7. 自己试一小步
  8. 查原始资料
  9. 找一份资料继续练
开始前,会这些就够了
  • 知道服务会接收请求,数据库可能暂时不可用;示例只需能运行 Python
遇到不熟悉的词,先看这 1 个解释
就绪检查
就绪检查用来判断一个服务实例现在是否适合接收流量。它可以考虑业务需要的条件,而不只是问进程是否还在运行。
打开完整术语小抄 ↗

一个服务的健康页一直返回 200,用户提交表单却总失败,可能并不矛盾:健康页只证明它检查的那一小段成功了。若它只回一行固定文字,就没有证明表单能写进数据库。

探针是定期替系统问一个小问题的检查。问题问得不同,失败后的动作也应不同;不能把所有异常都归为“赶快重启”。

先看这一页究竟检查了什么

Kubernetes 的 HTTP 探针按收到的状态码判断,成功范围是大于等于 200、且小于 400。通过这项检查,只表示满足该探针的约定,不是替全部业务盖章。

还要核对健康页经过哪条路。Spring Boot 文档提醒:若管理接口和业务接口使用不同端口与处理组件,管理页可用时,业务侧仍可能接不了连接。因此应同时观察用户真正需要的业务结果。

三个检查,分别决定不同事情

startup 问“启动准备做好了吗”。配置它之后,启动检查尚未成功时,不执行 liveness 和 readiness 检查。启动成功后,它完成自己的任务,不会一直替代后两者。

liveness 问实例本身是否还能继续工作。连续失败达到配置门槛后,会触发容器终止,并按重启策略处理。

readiness 问现在是否适合接收流量。检查失败后,负责分配常规流量的 Service 会避开未就绪实例;这项失败本身不要求重启。

用五张状态卡拆开判断

下面主动约定:启动已通过、实例自身正常,而且数据库可用或业务允许不用数据库,才算就绪。local_ok 是预先给定的“自身能继续工作”,不是只看进程存在;db_required=False 则表示已经另有可接受的处理方式。

函数只读取布尔值。waiting 表示启动尚未通过,finished 表示先前已通过;not-run 表示另外两类检查暂不运行。它没有计时、发 HTTP 请求、累计失败次数或执行重启,也没有模拟 Kubernetes 的完整流程。

小实验 · python
def assess(startup_passed, local_ok, db_ok, db_required):
    flags = (startup_passed, local_ok, db_ok, db_required)
    if any(type(value) is not bool for value in flags):
        raise ValueError("all state flags must be bool")

    # Assume all three probes are configured. This is not a scheduler.
    if not startup_passed:
        return ("waiting", "not-run", "not-run")

    ready = local_ok and (db_ok or not db_required)
    return (
        "finished",
        "pass" if local_ok else "fail",
        "pass" if ready else "fail",
    )


def main():
    cases = [
        ("starting", False, True, True, True),
        ("normal", True, True, True, True),
        ("database-down", True, True, False, True),
        ("usable-fallback", True, True, False, False),
        ("local-stuck", True, False, True, True),
    ]
    print("scenario | startup | liveness | readiness")
    for name, *flags in cases:
        print(" | ".join((name, *assess(*flags))))


if __name__ == "__main__":
    main()

怎样运行:Python 3.10+ 标准库;保存为 probe_states.py,运行 python probe_states.py。只计算虚构状态,不需要 Kubernetes、Spring Boot 或联网。

运行后对照结果
scenario | startup | liveness | readiness
starting | waiting | not-run | not-run
normal | finished | pass | pass
database-down | finished | pass | fail
usable-fallback | finished | pass | pass
local-stuck | finished | fail | fail

数据库坏了,先决定还能提供什么

示例的数据库故障不会让 liveness 失败。重启应用无法自动修好外部数据库;若所有实例都把同一个数据库放进存活检查,一次共享故障可能让它们一起反复重启,增加恢复负担。

要不要把数据库放进 readiness,则取决于业务是否必须依赖它、能否提供可接受的替代行为,以及全部实例同时退出流量后会怎样。Spring Boot 的这两个探针分组默认不会自动加入其他健康指标;需要按用途选择,不能照搬一个包罗全部依赖的健康总分。

记住这三点

  • 健康页成功,只能说明它实际检查到的范围。
  • 启动、存活和就绪对应不同问题;就绪失败本身不等于应该重启。
  • 共享依赖故障应结合业务可用范围判断,别让所有实例同时无效重启。

别把例子用过头

  • 本例是手写判断表,不包含探针周期、超时、失败阈值、重启策略或控制器传播时序。
  • 允许不依赖数据库的分支,是已经存在可接受处理方式的假设,不会自动让写入业务变得可用。
  • 就绪状态与业务结果仍需持续观察,一次通过不保证后面的每个请求都成功。

自己试一小步

一个服务既提供本地帮助页,又提交必须落库的申请,数据库暂时断开时该怎样设计检查?

  1. 先列出哪些能力仍可用、哪些已经无法完成,并写清用户是否接受这种限制。
  2. 分别写出启动、存活与就绪需要的证据,不先从状态码开始猜。
  3. 再考虑多个实例共用同一数据库时,全部退出流量或一起重启各会造成什么。

做到这些,就算完成

  • 没有把一个固定 200 当成完整业务验证。
  • 能说清判断针对实例自身还是外部依赖。
  • 把自己的取舍与 Kubernetes 实际触发动作所需的配置、时序分开。

查原始资料

想确认一个细节,先看这份资料对应的部分,不必从头读完所有文档。

  • Kubernetes:Liveness, Readiness, and Startup Probes (新标签页)↗Kubernetes · 英文

    三种探针的用途、startup 成功前的抑制、HTTP 200≤状态码<400,以及失败阈值和就绪失败后的处理。

    2026-09-26 已读 Types of probe、Check mechanisms、Configure Probes 的对应段落;只作规则说明,未部署集群或复现时序。

  • Spring Boot:Endpoints / Kubernetes Probes (新标签页)↗Spring · 英文

    探针分组默认范围、独立管理端口的局限,以及 liveness 避免外部依赖、readiness 权衡必需依赖和共享故障。

    2026-09-26 已读 Kubernetes Probes 与 Checking External State With Kubernetes Probes;未把文档建议说成运行中的自动配置,也未启动 Spring 应用。

找一份资料继续练

先选一项,按下面的范围继续学;不必从头读完整门课程。