服务启动时应显式调用 db.PingContext(ctx, timeout) 检查 MySQL 连通性,超时设为 3–5 秒,失败则 os.Exit(1);Redis 需用 client.Ping(ctx).Err() 并加最多 2 次重试;HTTP 依赖优先调用 /health 端点并设独立超时;多依赖检查宜用 errgroup.Group 并发控制,避免共用 context;所有依赖检查通过后仍需合理配置连接池参数。

服务启动时怎么判断 MySQL 连不上?
直接连一次,别等第一个 HTTP 请求才暴露问题。Go 的 sql.Open 不真连数据库,它只校验 DSN 格式;真正建连发生在第一次 db.Ping() 或执行查询时。
- 启动阶段必须显式调用
db.PingContext(ctx, timeout),超时建议设为 3–5 秒,避免卡死 - 如果 MySQL 宕机或网络不通,
Ping会返回"dial tcp: i/o timeout"或"connection refused",这时应立刻os.Exit(1) - 别在
init()里做这事——依赖注入容器(如 Wire)或main()开头才是合理位置 - 注意:MySQL 连接池默认最大空闲连接数是 2,但
Ping只用一个连接,不影响后续业务流量
Redis 启动检查为什么总超时失败?
常见错在用 redis.NewClient 后没等连接就去 client.Ping(),而客户端默认是懒连接(lazy connect),首次命令才拨号。
- 务必设置
ctx并带超时:client.Ping(ctx).Err(),否则可能卡住几十秒(取决于系统 TCP 超时) - 推荐加一层重试逻辑(最多 2 次),因为 Redis 启动略慢于 Go 进程,单纯失败退出太激进
- 若用的是
github.com/redis/go-redis/v9,确认没漏掉WithContext配置项;老版本v8的SetContext行为不一致,容易误判 - 别用
client.ConfigCheck()—— 它只校验配置结构,不测连通性
HTTP 依赖服务(如下游 API)怎么健康检查?
不能只看 http.Get 是否返回 200,得区分「服务存在」和「服务可用」。
- 优先调用对方提供的
/health或/readyz端点,而不是随便一个业务接口 - 自己构造请求时,必须设
context.WithTimeout,且超时时间 ≤ 启动容忍上限(比如整体启动窗口是 10 秒,单个依赖检查别超 3 秒) - 遇到
"net/http: request canceled (Client.Timeout exceeded while awaiting headers)"就说明超时了,不是网络问题就是对方没响应 - 如果下游没健康接口,至少验证响应体是否含关键字段(比如 JSON 中的
"status": "ok"),避免200却返回错误页
多个依赖串行检查太慢,能并发吗?
可以,但并发检查不等于无脑 go 启协程——每个检查仍需独立上下文控制,且失败要能快速终止整个启动流程。
立即学习 “go 语言免费学习笔记(深入)”;
- 用
errgroup.Group最稳妥:eg.Go(func() error {return checkMySQL() }),任一失败自动 cancel 其他 - 每个检查函数内部必须用自己带 timeout 的
context,不能共用一个长生命周期 context,否则某个慢依赖会拖垮全部 - 并发数别硬设成
runtime.NumCPU()——依赖检查基本是 I/O 密集,2–4 并发足够,再多只是增加连接竞争 - 注意:gRPC 依赖检查要用
cc.Connect()+cc.WaitForStateChange(),不是简单grpc.Dial就完事
最常被忽略的是:检查通过后,依赖实例本身没做复用或连接复用配置(比如 MySQL 的 SetMaxOpenConns 默认是 0,意味着无限),这会让服务跑着跑着突然卡住。启动检查只是第一道门,不是免检通行证。