/health 和 /health/ready 的分工:探针接进告警之前该知道什么

发布时间:2026/10/1 18:35:53
/health 和 /health/ready 的分工:探针接进告警之前该知道什么 Kubernetes 的 liveness 和 readiness 配错了后果远不止少了一个健康检查这么简单Pod 可能被反复重启或者流量被发给一个根本没在服务的实例。RustFS 把这两个概念拆成了两个端点分别对应文档里说的存活性和就绪性。接进告警之前先搞清这两者的差别免得回头排查时才发现方向错了。两个判定两批端点RustFS 的 S3 监听器默认 9000上注册了一批无需认证的探针端点由RUSTFS_HEALTH_ENDPOINT_ENABLE控制默认true。端点含义GET /health、HEAD /health、GET /health/live、GET /minio/health/live存活性进程在就返回 200GET /health/ready就绪性仅当存储、IAM 和对等节点健康时才 200否则 503GET /minio/health/ready上面那条就绪探针的 MinIO 兼容别名GET /minio/health/cluster、/minio/health/cluster/read集群读写健康另外需要锁仲裁GET /rustfs/console/health9001 控制台监听器控制台进程健康存活性那组只看进程活着。进程起来了但存储还没挂载、IAM 还没加载完这一组依然返回 200。就绪性那组才会去看后端依赖。两者放进 K8s 里前者对应 liveness、后者对应 readiness拿存活检查去读就绪端点会在启动阶段把还未就绪的 Pod 判死并重启拿就绪检查去读存活端点则等于放弃了任何依赖健康检查。探针不认证端口暴露要挑这批端点注册时不需要认证这一点在文档里是明写的。含义是任何能连到 9000 的人都能查到集群的健康状态包括降级原因这类内部信息。9000 是 S3 端口通常暴露给应用所以这里的安全边界要靠网络层来做而不是靠 RustFS 自己。控制台那个监听器是另一条边界。文档给的建议是 9001 只向可信网络暴露如果根本不需要控制台就设RUSTFS_CONSOLE_ENABLEfalse并把端口留着不放行。两行 firewalld 就能把这件事固定在系统上firewall-cmd--permanent--add-port9000/tcp firewall-cmd--permanent--add-port9001/tcp firewall-cmd--reload9000 需要对外放行的理由很充分它同时承载 S3 对象 API、管理 API 和内部节点 RPC。9001 没有这个理由。503 响应里那几个原因码才是能用的部分就绪探针在降级时返回 503并且给出每个依赖的明细。文档写明details对象报告storage、iam、lock三项配置了 KMS 时还会多一项kmsdegradedReasons里给出机器可读的原因例如storage_quorum_unavailable、iam_not_ready、lock_quorum_unavailable。这一段才是告警接入时真正要解析的东西。只看状态码的话503 和 503 之间没有区别运维只能知道不健康解析原因码之后可以分别对应到不同的处置路径存储仲裁不可用要去看盘和池IAM 未就绪要去看身份后端锁仲裁不可用通常意味着对等节点之间没有形成多数派。curl-shttp://node:9000/health/ready|jq.curl-fsShttp://node:9000/health/ready第一条把明细打出来给人看第二条只取状态码给进程判定。两条命令的同时存在也就说明了这两类消费方脚本和 K8s 探针只需要后者人排查的时候才需要前者。缓存一秒别把探针当成实时检查RUSTFS_HEALTH_READINESS_CACHE_TTL_MS默认值是1000即就绪探针结果的缓存有效期是 1 秒。文档写明这是就绪探针结果的缓存 TTL。这个默认值对告警频率有直接影响。如果一个节点刚从降级恢复1 秒内重复探测会拿到同一个缓存结果反过来节点刚降级时也会被缓存住 1 秒。对秒级的心跳检查来说这个窗口可以忽略对每 5 秒探测一次的采集任务缓存意味着采到的点可能是 1 秒前的状态。要留意的是反方向。这 1 秒缓存是探针对存储层的减压手段把 TTL 压到很小等于把这层减压去掉探测请求多来一次就多走一次完整的依赖检查要过存储仲裁、锁、对等节点这几关。单节点上这点开销看不出来一个几十 Pod 的集群被 kubelet 同时探一遍探测本身就开始和业务请求抢资源。TTL 从 1000 压到 100探测频率提高十倍代价也放大十倍。想更即时先看能不能把探测周期本身放长一点而不是把缓存压到几乎没有。和它配套的是RUSTFS_HEALTH_CLUSTER_TIMEOUT_MS默认值2000文档写明这是集群健康检查/minio/health/cluster的超时时间。这个参数管的是等待不是缓存。探针放进编排系统之后的常见错法第一种是把就绪端点配成存活探针。启动阶段存储还没挂上、IAM 还没加载完就绪端点返回 503编排系统按存活失败处理就会杀掉这个实例并重启重启之后仍然是同样状态于是陷入反复重启。这个错法在冷启动时最容易复现表现像服务起不来实际是配置配错了。第二种反过来把存活端点配成就绪探针。进程在就返回 200于是流量在实例还没真正能服务时就被放进来了表现为请求超时。这种错法不会在启动日志里留下任何错误信息只能靠客户端报错反向定位。第三种是把探测间隔压到缓存 TTL 以下。上面那个 1000 意味着间隔比 1 秒还短时前后几次探到的是同一份缓存结果探测得再勤也只反映 1 秒之内的状态。启动阶段还有第三个时间参数RUSTFS_STARTUP_READINESS_MAX_WAIT_SECS默认值120文档的解释是就绪探针报告 “starting” 的最长时间超过之后启动被视为失败。这条规则约束的是启动窗口但约束只发生在服务端。一个节点首次启动时如果磁盘挂载慢、IAM 后端连不上就绪探针会持续报告启动中120 秒之后不再这么报告启动即被判失败。进程本身不会因此退出真正把容器重启掉的是外层编排策略。所以这个窗口实际有多长是两段相加的结果服务端愿意等多久加上编排平台判定启动失败要多久。官方 Helm chart 的默认配置里只有 liveness 和 readiness 两个探针没有 startupProbe。liveness 那一组是 initialDelaySeconds30、periodSeconds5、failureThreshold3也就是容器起步之后第 45 秒左右就会因为连续三次失败而动手重启。这个数比服务端留的 120 秒短了一大截。冷启动慢的场景正好卡在这个缺口里。磁盘挂载、IAM 后端连通、节点之间互相发现三件事叠起来超过 45 秒却不到 120 秒是很常见的于是 Pod 在还来得及就绪之前就被重启重启后重走一遍同样的流程。表现是 Pod 反复重启而且看不到明确报错日志里只有一轮又一轮的启动信息很容易被当成服务本身起不来。补一个 startupProbe 可以把这段窗口交回给容器自己管。编排平台的启动判定窗口是 failureThreshold 乘 periodSeconds配 startupProbe 时让这个乘积不小于服务端的 120 秒超出的部分由 startupProbe 兜着。按 periodSeconds10、failureThreshold20配出来是 200 秒比服务端宽裕按 10 和 3 配出来只有 30 秒反而比原来更紧。startupProbe 判定失败同样会重启容器重启后启动预算重新计数。慢启动环境下一次不够就等下一轮这是它想要的效果跟启动失败区分开就行。集群读写健康要多一层/minio/health/cluster和/minio/health/cluster/read检查的是集群级别的写入和读取健康文档特别注明这两条还额外要求锁仲裁。这两条端点适合放进能反映能不能写的监控里因为它们看的是 quorum 而不是单个节点的进程状态。开销上它们的量级和/health/ready不在一个位置。锁仲裁意味着这条请求要问到其他节点才算数不像/health/ready只核对本节点那几项依赖。这个差别在参数上留了痕迹/minio/health/cluster有独立的RUSTFS_HEALTH_CLUSTER_TIMEOUT_MS默认2000毫秒管它的采集超时/health/ready没有这一项。所以这两条不适合跟就绪探针一个频率去探。每个节点几十秒探一次把锁仲裁的开销按同样的频率付一遍探测就从看一眼状态变成了一笔固定成本。按几十秒的间隔用它们回答集群现在能不能写比高频探测划算也不容易在降级时把 RPC 打满。单独看单节点的就绪探针是不够的所有节点都返回 200仍然可能出现整个集群写不进去的情况。要覆盖这层得同时盯/health/ready和/minio/health/cluster两组。除了探针还有一个更全面的核对手段rc admin info cluster rustfs。它会给出集群状态、RustFS 版本、服务器与磁盘数量、后端类型和纠删奇偶节点列表里能看运行时长、网络连通性、磁盘可用性和池成员归属。把它的输出当成健康真相比任何一个探针的瞬时返回值都更全面。探针适合回答现在能不能服务不适合回答为什么降级。后者要看details里那几项依赖前者只看端点。还有一层取舍在探针这一组。RUSTFS_HEALTH_ENDPOINT_ENABLE默认true注册的是无需认证的探针。部署在不受信任的网络里把它设成false、改由内部监控系统主动采集是更保守的做法。关之前先确认编排系统不再依赖这些路径。关掉之后这些探针路径不再提供Kubernetes 那类 httpGet 探针会拿到 404按失败处理容器随即重启重启后仍然探不到Pod 一直在起不来的状态。这类故障的表现是没人动过配置但 Pod 开始重启循环排查时容易往存储和网络方向找。真要关探针得改成在容器里执行命令的方式脚本内部用rc这类客户端去查而不是从外部发 HTTP 请求。落地细节还有一条。探针的响应体里有details和degradedReasons两段信息采集脚本最好把原因码单独取出来存而不是整段 JSON 塞进时序数据库。原因码的取值集合很小单独存之后可以按原因聚合哪一类降级集中出现一眼可见。