HPA要求指标端点必须为/metrics且符合OpenMetrics规范,不可用/healthz或/debug/pprof;自定义指标需通过Prometheus采集并正确配置metric.type与目标值;Pod须设置resources.requests;SIGTERM需妥善处理以保障优雅缩容;KEDA依赖服务主动上报queue_length等业务指标。

HPA 要求的指标端点必须是 /metrics,不是 /healthz 或 /debug/pprof
很多人混淆健康检查和扩缩容指标:HPA 默认只认 metrics-server 抓取的 CPU/内存数据;若想按 QPS、延迟或队列长度伸缩,必须让 Prometheus 能抓到你的 /metrics,且格式严格符合 OpenMetrics 规范。
常见错误是把 pprof 的 /debug/pprof/ 当成指标源——它不提供聚合业务指标,HPA 无法解析;或者把 /healthz 返回值硬塞进指标逻辑里,导致 HPA 报错 failed to get scale subresource。
- 用
prometheus/client_golang注册http_requests_total(Counter)、http_request_duration_seconds(Histogram)等标准指标 - 确保 HTTP handler 是
promhttp.Handler(),不是自定义 JSON 输出 - Pod 必须设置
resources.requests(如cpu: 100m),否则 metrics-server 拒绝采集 - 在 K8s 中部署
kube-metrics-adapter,并配置 Prometheus 为指标源,HPA 才能读取http_requests_total这类自定义指标
触发条件写错会导致 HPA 不扩容,比如用 averageValue 却没配 targetAverageValue
HPA YAML 里指标类型和目标值必须严格匹配。例如你想按 QPS > 100 就扩容,不能只写 averageValue: "100",还必须指定 metric.type: Object 或 metric.type: Pods,并确保指标名与 Prometheus 中暴露的一致(大小写、下划线都敏感)。
典型失败现象:HPA status 显示 unknown 或 no metrics,kubectl describe hpa 报错 did not find any metrics。
立即学习“go语言免费学习笔记(深入)”;
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 基于 Pod 级别指标(如单实例 QPS)用
type: Pods,目标字段是targetAverageValue - 基于整个 Deployment 的总量(如总请求数)用
type: Object,目标字段是targetValue - 指标名称必须与 Prometheus 中
http_requests_total完全一致,不能写成http_requests或requests_total - 避免用
Utilization类型套业务指标——它只适用于 CPU/memory,对 QPS 无效
SIGTERM 处理不到位,缩容时请求直接中断
K8s 缩容时发 SIGTERM,然后等 terminationGracePeriodSeconds(默认 30s)后强杀。如果 Go 服务没监听该信号,或没调用 http.Server.Shutdown(),正在处理的请求会被立即切断,客户端收到 502 Bad Gateway 或连接重置。
关键不是“有没有关 server”,而是关得是否干净:DB 连接池、消息消费者、长轮询 goroutine 都得同步退出。
- 用
signal.Notify(c, syscall.SIGTERM, syscall.SIGINT)捕获信号 -
srv.Shutdown()必须传带超时的context.WithTimeout(),否则可能永远卡住 - 在 Shutdown 前关闭所有依赖资源:调用
db.Close()、consumer.Stop()、取消后台 ticker - 就绪探针(
readinessProbe)必须指向/healthz,且该接口在 Shutdown 开始后立即返回 503,让反向代理立刻摘流
KEDA 基于队列长度扩缩时,queue_length 指标必须由 Go 服务主动上报
KEDA 不拉取指标,而是轮询你暴露的端点(如 Redis LLEN、Kafka lag)。如果你的服务本身是消费者,又想根据“自己消费的队列积压”伸缩,就得在 Go 里实现一个轻量指标端点,实时计算并暴露 queue_length。
别指望 KEDA 自动猜出你的队列名或命名空间——每个 scaler 都要明确指定 metadata,且 Go 服务必须保证该指标低延迟、高可用。
- 用
prometheus.NewGaugeVec注册queue_length,key 包含队列名(如queue="order_events") - 每秒从 Redis/Kafka 获取一次积压数,用
gauge.WithLabelValues(...).Set(...)更新 - KEDA 的
ScaledObject中metadata.metricName必须与 gauge 名完全一致 - 避免在指标 handler 里做耗时操作(如查 DB),否则 KEDA 轮询超时,触发误缩容

















