go微服务健康检查必须分离/livez与/readyz:/livez仅轻量检查进程状态(如goroutine数、内存),响应≤1秒;/readyz须并行探测db/redis/grpc等依赖,任一失败返回503并带具体错误项,超时需独立设置。

Go 应用部署后能否被正确识别为“健康”,不取决于它是否能启动,而取决于你用什么探针、在哪暴露、检查什么——三者错一个,Kubernetes 就可能反复重启 Pod 或拒绝转发流量。
为什么 /healthz 不能直接调 db.Ping()
常见错误是把 liveness 探针写成依赖数据库连通性的 HTTP handler。这会导致:CrashLoopBackOff:DB 短暂抖动 → /healthz 返回 5xx → K8s 杀进程 → 新 Pod 启动仍连不上 DB → 循环重启。
- liveness 探针只应回答一个问题:“这个进程自己还活着吗?”——检查内存标志(如
atomic.LoadInt64(&healthy))、主 goroutine 是否卡死、或简单响应时间 ≤100ms - DB、Redis、外部 API 等必须挪到
/readyz(readiness)里,且要设短超时(如context.WithTimeout(ctx, 300*time.Millisecond))并容忍失败(返回 503 而非 panic) - 若框架用了 Gin/Echo,务必绕过中间件:
c.Status(200)或c.AbortWithStatus(200),避免日志/鉴权拖慢响应
instgo 编译期注入探针的实操要点
阿里云 ARMS 的 instgo 工具本质是在 go build 前插入 AST 分析阶段,自动埋点,无需改代码。但容易踩坑:
- 下载后必须
chmod +x instgo,且保存路径需对编译用户可写(否则自动更新失败) - 若项目含
vendor目录,命令得写成:instgo build -mod=vendor -o app .,漏掉-mod=vendor会走 proxy,导致探针注入失败 -
instgo set --uid=123456必须在构建前执行;若跳过,探针会尝试拉取最新版,但内网环境可能因无法访问 OSS 而卡住编译 - 不支持 macOS/Windows 宿主机上构建 ARM64 镜像(
instgo本身无跨平台交叉编译能力),ARM64 机器必须用原生instgo-linux-arm64
eBPF 探针在腾讯云上的权限与路径陷阱
腾讯云 eBPF 探针(otel-go-instrumentation)不改源码、不重编译,但对运行时环境更敏感:
- 必须用
sudo启动:sudo OTEL_GO_AUTO_TARGET_EXE=/path/to/your/app ./otel-go-instrumentation;普通用户权限下 eBPF 程序加载失败,日志里只显示operation not permitted,无其他提示 -
OTEL_GO_AUTO_TARGET_EXE必须是**绝对路径**,且该二进制文件不能是 symlink(eBPF 加载器不解析符号链接) - 仅支持 Linux 内核 ≥4.19;在 Docker Desktop for Mac/Windows 上跑的容器,底层仍是 macOS/Windows 内核,eBPF 不生效——此时必须换 SDK 接入方式
- 上报 endpoint 若选“内网”,
OTEL_EXPORTER_OTLP_ENDPOINT必须填 VPC 内可达地址(如http://arms-collector.internal:4317),填公网地址会因安全组拦截静默失败
自定义健康检查器别忽略 initialDelaySeconds
无论用 canary 库还是手写 /readyz,Kubernetes 探针配置里最常被忽视的是启动延迟:
- Go 应用冷启动耗时波动大(尤其带 gRPC server、DB 连接池预热),若
initialDelaySeconds: 5,而应用实际 8 秒才完成初始化,前 3 次 readiness 检查必失败 → Service endpoint 长期为空 → 流量 0 - 建议先压测确定真实就绪时间,再设
initialDelaySeconds为该值 +2 秒;liveness 则建议 ≥30 秒,避免误杀 - go-zero 等框架的
comboHealthManager默认串行执行所有Probe.IsReady(),若某探针阻塞(如未设 context timeout 的 Redis Ping),整个/readyz就超时 —— 每个检查必须自带超时和 recover











