自检模块应检查http健康端点响应、数据库连接、redis连通性、关键配置非空、本地磁盘空间;用标准库http.handlerfunc实现轻量/healthz端点,同步执行各检查项并捕获panic,任一失败返回503及错误详情。

自检模块该检查哪些核心项
系统自检不是堆功能,而是聚焦「启动即暴露问题」。Go 服务上线前最常卡在依赖不可用、配置缺失或资源不足上,所以必须检查:HTTP 健康端点是否能响应、database 连接是否可建立、redis 是否可 ping、关键配置字段是否非空(比如 APP_ENV)、本地磁盘剩余空间是否低于阈值(如 /tmp 小于 100MB)。
别检查 CPU 使用率或内存 RSS——这些属于运行时监控范畴,自检阶段查了也没法自动修复,反而拖慢启动。
用 http.HandlerFunc 实现轻量健康检查端点
不要引入额外框架或中间件,直接用标准库注册一个 /healthz 路由。它必须返回 200 OK 且响应体极简(例如纯文本 ok),避免 JSON 序列化开销和潜在 panic。
- 所有检查逻辑必须同步执行,不加 context.WithTimeout——超时应由调用方(如 Kubernetes liveness probe)控制
- 每个检查项单独 try-catch,用
recover()捕获 panic 并记录错误,但不中断后续检查 - 若任意一项失败,整体返回
503 Service Unavailable,响应体包含失败项名称(如database: dial timeout)
func healthzHandler(w http.ResponseWriter, r *http.Request) {
var errs []string
if err := checkDB(); err != nil {
errs = append(errs, "database: "+err.Error())
}
if err := checkRedis(); err != nil {
errs = append(errs, "redis: "+err.Error())
}
// …其他检查
if len(errs) > 0 {
http.Error(w, strings.Join(errs, "; "), http.StatusServiceUnavailable)
return
}
w.WriteHeader(http.StatusOK)
io.WriteString(w, "ok")
}
配置驱动的检查项开关与超时控制
硬编码检查逻辑会导致测试环境误报(比如测试不用连真实 DB)。用配置控制开关和超时参数更安全:
- 定义结构体字段如
CheckDB bool、DBTimeoutSeconds int,从Viper或os.Getenv加载 - 数据库检查必须显式设置
context.WithTimeout,且超时时间 ≤ KubernetesinitialDelaySeconds(常见设为 3 秒) - 文件系统检查用
syscall.Statfs获取可用空间,避免os.Stat误判挂载点状态 - 环境变量检查只校验必需字段是否存在且非空,不校验格式(如邮箱、URL)——那是启动后业务逻辑的事
启动时阻塞自检 vs 后台异步预热
90% 的 Go 服务应该选择「启动时阻塞自检」:在 main() 中调用自检函数,成功才启动 HTTP server。这样能确保容器就绪探针(readiness probe)一上来就返回 200,避免流量打入未就绪实例。
只有两种情况考虑后台异步:
- 检查项耗时长(如连接第三方 API),且业务允许部分功能降级启动(此时需在
/healthz中区分liveness和readiness状态) - 检查依赖本身是本服务启动后才初始化的(比如 gRPC client 需先注册服务发现),这时必须把检查逻辑移到依赖初始化之后
注意:异步检查必须带重试机制(最多 3 次,间隔 1 秒),且失败后要写入全局状态供 /healthz 读取——否则探针永远看不到失败。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











