MinIO 健康检查端点全解:Liveness、Readiness 与 Cluster 探活机制的实战指南
MinIO 在无认证状态下暴露了五个健康检查端点(/minio/health/live、/minio/health/ready、/minio/health/cluster、/minio/health/cluster/read),它们是 Kubernetes 编排、服务网格流量治理与节点下线维护的核心探测入口。本文基于仓库文档 docs/metrics/healthcheck/README.md,逐端点解析其探测语义、返回码规则、响应头信息,并结合 cmd/healthcheck-handler.go、cmd/healthcheck-router.go 与 cmd/erasure-server-pool.go 的源码实现,讲清每个端点"什么时候返回 200、什么时候返回 503/412/503 Busy",以及维护模式下如何安全地把一个 MinIO 节点从集群中摘除。
端点总览与路由注册
MinIO 的健康检查端点全部挂载在保留桶路径前缀 /minio/health 之下。该前缀来自保留桶名 minio(minioReservedBucket = "minio",见 cmd/generic-handlers.go 第 144-145 行)。路由注册在 cmd/healthcheck-router.go 中完成:
const (
healthCheckPath = "/health"
healthCheckLivenessPath = "/live"
healthCheckReadinessPath = "/ready"
healthCheckClusterPath = "/cluster"
healthCheckClusterReadPath = "/cluster/read"
healthCheckPathPrefix = minioReservedBucketPath + healthCheckPath
)
每个端点同时注册了 GET 和 HEAD 两种方法(便于 Kubernetes 用 httpGet 探活),并统一包裹了 httpTraceAll 中间件。这些端点不需要任何认证凭据,可以直接用 curl 或负载均衡器的健康检查任务访问:
| 端点 | 方法 | 语义 | 成功 | 失败 |
|---|---|---|---|---|
/minio/health/live |
GET / HEAD | 存活探测(liveness) | 200 | 503(服务未初始化/过载) |
/minio/health/ready |
GET / HEAD | 就绪探测(readiness) | 200 | 503(etcd/KMS 不可达、过载) |
/minio/health/cluster |
GET / HEAD | 集群写多数派探测 | 200 | 503(维护模式为 412) |
/minio/health/cluster/read |
GET / HEAD | 集群读多数派探测 | 200 | 503(维护模式为 412) |
Liveness 探测:/minio/health/live
文档对 liveness 的定义是:该端点总是返回 200 OK,只有在配置了 etcd 且 etcd 不可达时才会失败;探测失败时,Kubernetes 等平台会重启容器。配套的 Kubernetes 探针配置为:
livenessProbe:
httpGet:
path: /minio/health/live
port: 9000
scheme: HTTP
initialDelaySeconds: 120
periodSeconds: 30
timeoutSeconds: 10
successThreshold: 1
failureThreshold: 3
各参数含义:initialDelaySeconds: 120 给 MinIO 留出启动与元数据初始化的时间;periodSeconds: 30 是探测周期;timeoutSeconds: 10 是单次探测超时;failureThreshold: 3 意味着连续 3 次失败(即 90 秒)才会触发容器重启。
源码层面,cmd/healthcheck-handler.go 中的 LivenessCheckHandler 比文档描述的检查逻辑更完整:
- 对象层未就绪:
newObjectLayerFn()返回nil时,响应头写入x-minio-server-status: offline,表明服务尚未初始化完成; - 节点间互调豁免:如果请求带有 MinIO 内部节点间调用的标记头(
MinIOPeerCall),直接返回 200,避免内部探测被负载状态干扰; - 请求队列过载:当前排队中的 S3 请求数
globalHTTPStats.loadRequestsInQueue()超过 API 并发池容量globalAPIConfig.getRequestsPoolCapacity()时,返回ErrBusy(HTTP 503)。这是一个保护机制——进程活着但已无法承接新请求时,编排平台应介入; - 以上均通过则返回
200 OK。
值得注意的是源码注释明确指出:liveness 与 readiness 的关键差异在于 liveness 失败会导致 Pod 重启,因此它刻意不联系任何外部系统(如 KMS),只检查本进程的存活与负载状态。
Readiness 探测:/minio/health/ready
Readiness 探测用于决定流量是否应该路由到该容器——文档说明失败时 Kubernetes 会关闭对该容器的路由。Kubernetes 探针配置:
readinessProbe:
httpGet:
path: /minio/health/ready
port: 9000
scheme: HTTP
initialDelaySeconds: 120
periodSeconds: 15
timeoutSeconds: 10
successThreshold: 1
failureThreshold: 3
与 liveness 相比,readiness 的探测周期更短(periodSeconds: 15),因为它的失败后果只是摘除流量(而非重启),探测可以更密集。
ReadinessCheckHandler(cmd/healthcheck-handler.go)在过载检查之外,还额外执行两类外部依赖检查:
- KMS 可达性:如果配置了 KMS(
GlobalKMS != nil),会在 1 分钟超时内调用GenerateKey做一次密钥生成测试;失败则返回对应的 API 错误码。这保证挂载加密桶的对象流量不会被路由到无法解密的节点; - etcd 可达性:如果配置了 etcd(
globalEtcdClient != nil),会以defaultContextTimeout的超时执行一次Get("health")(借鉴 etcdctl 的endpoint health命令实现);不可达则返回错误,这正是文档所说"Only fails if etcd is configured and unreachable"的出处。
此外,与 liveness 相同的过载保护(队列长度超过并发池容量即返回 503 Busy)在 readiness 中同样生效。GET 请求会返回完整的 S3 风格 XML 错误体,HEAD 请求则只带状态码。
Cluster 探测:/minio/health/cluster(写多数派)
集群级探测回答的问题是:接收请求的这个节点所在集群,当前是否还具备对象写入能力? 集群具备写多数派(write quorum)时返回 200 OK,否则返回 503 Service Unavailable。文档给出的 503 示例:
curl http://minio1:9001/minio/health/cluster
HTTP/1.1 503 Service Unavailable
Accept-Ranges: bytes
Content-Length: 0
Server: MinIO
Vary: Origin
X-Amz-Bucket-Region: us-east-1
X-Minio-Write-Quorum: 3
X-Amz-Request-Id: 16239D6AB80EBECF
X-Xss-Protection: 1; mode=block
Date: Tue, 21 Jul 2020 00:36:14 GMT
ClusterCheckHandler(cmd/healthcheck-handler.go)的执行流程:
- 先经
checkHealth(w)做前置检查:对象层未初始化返回 503 并带x-minio-server-status: offline;globalBucketMetadataSys或globalIAMSys未完成初始化时,分别返回x-minio-server-status: bucket-metadata-offline或iam-offline(cmd/healthcheck-handler.go); - 给探测上下文加上
globalAPIConfig.getClusterDeadline()超时,默认 10 秒(可经 API 子系统的cluster_deadline配置项 / 环境变量MINIO_API_CLUSTER_DEADLINE调整,默认值"10s",见 internal/config/api/api.go 与 cmd/handler-api.go); - 解析查询参数
maintenance(布尔)与deployment-type,调用对象层的Health(ctx, opts)得到HealthResult; - 无论健康与否,都会写入三个响应头:
x-minio-write-quorum:该集群要求的写多数派数量(示例中为 3);x-minio-storage-class-defaults:当配置加载失败而使用默认存储类时为true;x-minio-healing-drives:有盘正在纠删自愈时返回其数量;
- 不健康时:普通探测返回
503 Service Unavailable,维护模式(?maintenance=true)返回412 Precondition Failed。
多数派判定的源码逻辑
真正的多数派计算在 erasureServerPools.Health(cmd/erasure-server-pool.go)中完成,其核心算法值得展开:
- 调用
StorageInfo(ctx, false)拿到全集群所有盘的在线状态,按"池(pool)→ 纠删集(set)"维度统计每个集合中DriveStateOk的在线盘数online与正在自愈的盘数healing; - 从
BackendInfo()读取每个池的StandardSCData(数据盘数 N)与StandardSCParity(奇偶校验数 W)。读多数派 = N,写多数派 = N;若 N == W(即无校验的极限配置),写多数派取 N+1; - 对每个池、每个纠删集分别判断:
online >= 写多数派决定该集的写健康,online >= 读多数派决定读健康;任一个纠删集不满足,则整个集群标记为不健康(result.Healthy为各集结果的 AND); - 写健康日志级别是
logger.FatalKind,读健康是普通告警,二者都会记录"期望多数派 vs 在线盘数",便于排障。
以常见的 4 数据盘 + 2 校验盘纠删集为例,读多数派为 4、写多数派为 4,即每个纠删集至少 4 块盘在线,集群探测才返回 200。
Cluster 读探测:/minio/health/cluster/read
/minio/health/cluster/read 与写探测共用同一套 Health 计算,但判定的是读多数派:具备读多数派返回 200 OK,否则 503 Service Unavailable(维护模式下为 412):
curl http://minio1:9001/minio/health/cluster/read
HTTP/1.1 503 Service Unavailable
Accept-Ranges: bytes
Content-Length: 0
Server: MinIO
Vary: Origin
X-Amz-Bucket-Region: us-east-1
X-Minio-Write-Quorum: 3
X-Amz-Request-Id: 16239D6AB80EBECF
X-Xss-Protection: 1; mode=block
Date: Tue, 21 Jul 2020 00:36:14 GMT
ClusterReadCheckHandler(cmd/healthcheck-handler.go)与写探测的差异在于:判定条件使用 result.HealthyRead,响应头写的是 x-minio-read-quorum 而非 x-minio-write-quorum。由于读多数派要求不低于写多数派(多数配置下两者相等),该端点适合让只读客户端(如报表、备份读)独立探测集群的读服务能力。
维护模式:安全地把节点下线
这是文档中最实用的场景:下线某节点做维护之前,先向该节点询问"你可以被关机吗"。 查询方式为在集群探测上附加 maintenance=true:
curl http://minio1:9001/minio/health/cluster?maintenance=true
HTTP/1.1 412 Precondition Failed
Accept-Ranges: bytes
Content-Length: 0
Server: MinIO
Vary: Origin
X-Amz-Bucket-Region: us-east-1
X-Amz-Request-Id: 16239D63820C6E76
X-Xss-Protection: 1; mode=block
X-Minio-Write-Quorum: 3
Date: Tue, 21 Jul 2020 00:35:43 GMT
- 返回
412 Precondition Failed:下线该节点将导致集群失去写多数派(失去 HA),不要下线; - 返回
200 OK:下线后集群仍满足多数派要求,可以安全执行维护。
源码揭示了维护模式的两个额外语义(cmd/erasure-server-pool.go):
- 排除本节点自身的盘:
Health计算时,若opts.Maintenance为真,会把落在globalLocalDrivesMap中(即本机持有的盘)的盘从统计中剔除,模拟"本节点消失后"的集群状态再判断多数派——这正是文档所说"check if the node which received the request can be taken down for maintenance"的实现; - 自愈中的盘会使维护探测失败:
opts.Maintenance下还额外要求drivesHealing == 0(有盘正在纠删自愈则Healthy/HealthyRead一并置假,并通过x-minio-healing-drives头报告自愈盘数)。若同时指定deployment-type=vmware,还会记录自愈盘总数到日志——这是针对 vSphere 场景的额外观测点。
因此推荐的维护流程是:对目标节点执行 curl http://<node>:9000/minio/health/cluster?maintenance=true,得到 200 后再执行停止操作;得到 412 则说明当前节点不可摘除,应等待其他盘恢复或扩盘后再试。
配置与运行前提小结
围绕这些端点,源码中可以确认的运行前提与可调参数:
| 项目 | 说明 | 依据 |
|---|---|---|
| 端点前缀 | 全部位于保留路径 /minio/health/...,无需认证 |
cmd/healthcheck-router.go |
| 支持方法 | GET 与 HEAD,HEAD 仅回状态码,GET 失败时回 S3 风格错误体 | cmd/healthcheck-handler.go |
| 集群探测超时 | 默认 10 秒,可经 cluster_deadline / MINIO_API_CLUSTER_DEADLINE 调整 |
internal/config/api/api.go、cmd/handler-api.go |
| 过载保护 | 排队请求超过 API 并发池容量时,live/ready 返回 503(ErrBusy) | cmd/healthcheck-handler.go |
| etcd / KMS 检查 | 仅 readiness 端点执行,且仅在相应组件已配置时执行 | cmd/healthcheck-handler.go |
| 维护模式 | ?maintenance=true 剔除本节点盘并要求无盘自愈中;不安全时返回 412 |
cmd/erasure-server-pool.go |
需要说明的适用前提:以上行为以当前仓库源码为准。liveness 在"对象层未初始化、请求队列过载"等情况下也会失败,这是文档"always responds with 200 OK"之外的补充事实,来源为 LivenessCheckHandler 的实现;deployment-type 参数目前仅在 VMware 场景产生额外日志行为(从源码结构看)。
小结
MinIO 的健康检查体系分为三个层次:进程层(live——进程是否活着且不过载)、就绪层(ready——外部依赖 etcd/KMS 是否可用)、集群层(cluster/cluster read——纠删集是否满足写/读多数派)。三层分别对应 Kubernetes 的 livenessProbe、readinessProbe 和服务网格/负载均衡的集群级健康治理;而 ?maintenance=true 的 412/200 语义则为节点滚动维护提供了明确的安全性判据。掌握各端点的返回码、x-minio-write-quorum 等响应头以及 cluster_deadline 超时配置,就足以在编排环境中完成对 MinIO 集群的完整健康治理。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00