探针注册须异步重试且解耦主服务启动,区分 liveness 与 readiness 接口,注册中心操作需支持上下文取消,探针逻辑应封装为可复用组件并确保依赖检查带超时。

探针注册逻辑必须和主服务启动解耦
Go 服务常因探针初始化失败导致整个进程启动失败,比如 etcd 或 consul 临时不可达时,http.HandleFunc 还没注册完就 panic。正确做法是把探针注册放在独立 goroutine 中异步重试,主服务先启动监听,再“尽力而为”注册。
- 用
sync.Once控制探针初始化只执行一次,但注册动作可反复尝试 - 首次失败不 panic,记录 warn 日志并每 2–5 秒重试,直到成功或超时(建议设 30s 总超时)
- 探针 HTTP handler(如
/health)应在主服务http.Serve前就注册,否则健康检查端口根本不可达
健康检查接口要区分 Liveness 和 Readiness
很多封装只提供一个 /health,但 Kubernetes 等编排系统需要两个语义不同的端点:/live 检查进程是否存活,/ready 检查是否能处理请求。混用会导致滚动更新卡死或流量误切。
-
/live只做内存/协程数等轻量检测,绝不访问下游依赖(DB、Redis、其他服务) -
/ready必须检查关键依赖,例如ping数据库连接池、验证 RedisPING响应 - 返回状态码严格遵循:健康返回
200,不健康返回503;避免用4xx,否则会被误判为客户端错误
注册中心适配器必须支持上下文取消
服务关闭时,若注册中心注销逻辑没响应 context.Context,会导致 os.Exit 卡住或 goroutine 泄漏。常见错误是直接调用 client.Deregister() 而不传 cancelable context。
- 所有注册中心 client(如
registry.ConsulClient、registry.EtcdClient)的 Register/Deregister 方法都应接收ctx context.Context - 在
signal.Notify捕获os.Interrupt或syscall.SIGTERM后,用context.WithTimeout生成带超时的 cancel ctx 发起注销 - 注销失败不阻塞退出,记录 error 日志即可;注册中心本身有 TTL 自动清理机制
避免把探针逻辑硬编码进 main 包
直接在 main.go 里写 http.HandleFunc("/health", ...) 和 consul.Register(...),会导致模块无法复用、测试困难、升级成本高。真正可维护的封装必须导出干净的初始化函数。
- 定义结构体如
type Probe struct { LiveCheck, ReadyCheck func() error },通过字段注入检查逻辑 - 暴露
NewProbe(opts ...ProbeOption)和Probe.Install(httpMux *http.ServeMux)方法 - 注册中心适配单独抽成
Registerer接口,让使用者按需传入consul.Registerer或nacos.Registerer
最易被忽略的是:探针的依赖检查函数(如 DB ping)必须支持超时控制,否则一个慢查询会让整个 /ready 接口 hang 住。别忘了给每个依赖调用套上 context.WithTimeout。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











