iris 框架不提供开箱即用的自动健康检查,iris.healthcheck 仅为类型别名(func(iris.context) bool),不能直接作为 handler 使用;必须手动实现探针逻辑,如数据库连通性检测,并严格控制超时、避免阻塞与写操作。

直接用 iris.HealthCheck 中间件注册一个 /health 端点,但必须手动实现探针逻辑;Iris 不提供开箱即用的自动健康检查(如数据库连通性、磁盘空间等),所有探测行为需你编码控制。
为什么不能只写 app.Get("/health", iris.HealthCheck)
Iris 的 iris.HealthCheck 并不是一个可直接调用的函数,它只是个类型别名(type HealthCheck func(iris.Context) bool),本质是要求你传入一个返回 bool 的函数。常见错误是误以为它是内置 handler,结果编译报错:cannot use iris.HealthCheck (type iris.HealthCheck) as type iris.Handler。
正确做法是自己定义函数,并确保它:
- 接收 iris.Context 参数
- 返回 bool(true 表示健康)
- 内部可执行 DB ping、HTTP 依赖调用、文件读写等探测
- 不阻塞主线程(超时必须设限)
例如:
func dbHealth(ctx iris.Context) bool {
db := getDB() // 假设你有全局 *sql.DB
ctx.StatusCode(iris.StatusOK)
return db.PingContext(ctx.Request().Context()) == nil
}
<p>app.Get("/health", func(ctx iris.Context) {
if dbHealth(ctx) {
ctx.WriteString("OK")
} else {
ctx.StatusCode(iris.StatusServiceUnavailable)
ctx.WriteString("DB unreachable")
}
})
</p>
如何避免健康检查拖垮主服务
健康端点被监控系统高频轮询(如每 5 秒一次),若每次都同步执行耗时操作(比如连 Redis、查 MySQL),会导致 goroutine 积压、CPU 升高,甚至掩盖真实故障。
- 所有外部依赖调用必须带 context 超时,例如
ctx.Request().Context()配合context.WithTimeout - 不要在健康检查里做写操作(如写日志文件、发消息),只做只读探测
- 对慢速依赖(如第三方 API)建议缓存上次探测结果,用 goroutine 异步刷新,健康端点只读缓存值
- 避免使用
time.Sleep模拟探测——这会直接卡死该请求协程
需要区分 liveness 和 readiness 吗
需要。Kubernetes 等编排平台依赖这两个语义:
-
/livez:只确认进程是否存活(例如能响应 HTTP、未 panic)。可仅检查http.Server.Addr是否监听,不碰任何外部依赖 -
/readyz:确认服务是否就绪接收流量(例如 DB 连通、配置加载完成、依赖服务可达)。这才是上面dbHealth应该放的位置
两者应独立路由、独立超时策略、独立告警通道。别把 readiness 探针逻辑塞进 liveness——否则数据库抖动会导致整个 Pod 被反复重启。
日志和指标怎么接进去
Iris 自带 iris.Logger 中间件会记录所有请求,但健康端点流量大、无业务价值,全量记日志会污染 access log。建议:
- 用
ctx.Application().Logger().Infof手动打轻量日志(如 “/readyz OK”),不走默认 access log - 用 Prometheus client_golang,在健康函数内更新
prometheus.GaugeVec,例如health_status{endpoint="db"} 1 - 避免在健康 handler 里调用
ctx.JSON—— 它会触发 Content-Type 设置和 gzip 压缩,纯文本响应更快更省 CPU
真正容易被忽略的是:健康端点的响应体内容本身会被监控系统解析。如果返回 JSON 但字段不固定(比如有时带 details 有时不带),下游告警规则可能失效。保持响应格式稳定,比如始终返回 {"status":"ok","timestamp":1726850520}。











