Go服务必须在main()返回前完成关键依赖连通性验证,失败直接os.Exit(1);需用db.PingContext(ctx, 3*time.Second)显式探测,避免sql.Open假成功,并用errgroup.Group并发安全检查各依赖。

启动阶段就暴露依赖不可用,比滚动更新卡住或上线后报错更可控。Go 服务必须在 main() 返回前完成关键依赖连通性验证,失败直接 os.Exit(1),不留给 Kubernetes 拖着跑。
MySQL/PostgreSQL 启动检查为什么总卡住或误判
因为 sql.Open 不真连,只校验 DSN;真正建连发生在第一次 db.PingContext()。没设超时、没重试、没区分错误类型,就会卡死或过早退出。
- 必须显式调用
db.PingContext(ctx, 3*time.Second),超时设为 3–5 秒(别用默认零值) - 遇到
"dial tcp: i/o timeout"或"connection refused"立即os.Exit(1) - 别在
init()里做——它无法控制执行时机,应在main()开头或依赖注入容器初始化后 - 注意:MySQL 默认最大空闲连接数是 2,
Ping只用一个连接,不影响后续业务
Redis 连接检查总超时失败的三个原因
常见于用 github.com/redis/go-redis/v9 但没正确触发连接,或超时逻辑失控。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 客户端默认懒连接,
client.Ping(ctx)才真正拨号,必须传带超时的ctx - 推荐加最多 2 次重试(因 Redis 启动常略慢于 Go 进程),但每次重试都用新
context.WithTimeout - 别用
client.ConfigCheck()——它只校验结构,不测连通性;老版本 v8 的WithContext行为不一致,容易漏错
多个依赖怎么并发检查又不互相干扰
串行检查太慢,裸写 go 协程又难收敛错误。要用 errgroup.Group 控制生命周期和错误传播。
- 每个检查函数返回
error,如func() error { return db.PingContext(ctx, 3*time.Second) } - 用
eg.Go()并发启动,任一失败自动 cancel 其他协程,避免等待冗余超时 - 不要共用同一个
context.Background()——每个检查应有独立超时,比如 DB 3 秒、Redis 2 秒、gRPC 1.5 秒 - 失败日志必须包含具体依赖名和错误,例如
"failed to ping redis: context deadline exceeded"
/readyz 里为什么不能放启动检查逻辑
就绪探针不是启动检查的补丁。它的职责是“当前是否可收流量”,不是“能不能活下来”。混用会导致 K8s 在滚动更新中反复摘除、重建 Pod。
-
/readyzhandler 必须只读缓存状态,不能触发新连接、不能 reload 配置、不能预热缓存 - 所有依赖探测结果应由后台 goroutine 定期刷新(如每 5 秒一次),并用
sync.RWMutex保护读写 - 后台探测失败时,只更新缓存里的状态字段(如
{"db": "DOWN"}),不 panic、不 exit - 若你发现启动检查通过了,但
/readyz仍返回 503,大概率是缓存未更新或读锁没释放
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










