如何获取SQS的消息总数?以及如何解决基于SQS指标实现Kubernetes HPA合理扩缩容的问题?
你遇到的这个问题确实很典型——单独依赖ApproximateNumberOfMessagesVisible会导致Pod刚取到消息就被缩容(因为消息变为不可见),而只用ApproximateNumberOfMessagesNotVisible又没法触发扩容。除了自定义求和指标之外,这里有几个可行的解决方案:
1. 使用SQS自带的总消息数指标
AWS SQS其实在CloudWatch中提供了一个ApproximateNumberOfMessages指标,它正好是ApproximateNumberOfMessagesVisible和ApproximateNumberOfMessagesNotVisible的总和。直接用这个指标作为HPA的外部指标,就能同时反映队列中待处理和正在处理的总消息量,完美解决你的问题。
修改后的外部指标模板可以这样写:
apiVersion: metrics.aws/v1alpha1 kind: ExternalMetric metadata: name: sqs-total-messages spec: name: sqs-total-messages queries: - id: total_messages metricStat: metric: namespace: "AWS/SQS" metricName: "ApproximateNumberOfMessages" dimensions: - name: QueueName value: "queue_name" period: 60 stat: Average unit: Count returnData: true
对应的HPA配置只需要把metricName改成这个新指标即可。
2. 同时配置两个外部指标并设置合理权重
如果因为某些原因不能用总消息数指标,你可以在HPA中同时引入Visible和NotVisible两个指标,分别设置权重来平衡扩容和缩容逻辑:
kind: HorizontalPodAutoscaler apiVersion: autoscaling/v2beta1 metadata: name: hpa-name spec: scaleTargetRef: apiVersion: apps/v1beta1 kind: Deployment name: deployment-name minReplicas: 1 maxReplicas: 50 metrics: - type: External external: metricName: sqs-visible-messages targetAverageValue: 2 - type: External external: metricName: sqs-not-visible-messages targetAverageValue: 1
这里的思路是:用Visible消息数驱动扩容(当待处理消息增多时增加Pod),用NotVisible消息数来限制缩容(当还有大量正在处理的消息时,不会轻易减少Pod)。你可以根据实际业务调整targetAverageValue的数值,找到适合的平衡。
3. 调整可见性超时和HPA缩容冷却时间
另一种思路是通过调整SQS的消息可见性超时(Visibility Timeout)和HPA的缩容冷却时间(scaleDownStabilizationWindowSeconds)来避免过早缩容:
- 调整可见性超时:把消息的可见性超时设置得比Pod处理单条消息的时间长一些,确保Pod在处理完消息并删除它之前,消息不会重新变为可见。这样
ApproximateNumberOfMessagesVisible不会因为Pod取走消息就立即下降,给HPA足够的时间判断是否需要缩容。 - 设置缩容冷却时间:在HPA配置中添加
scaleDownStabilizationWindowSeconds,让HPA在缩容前等待一段时间,确保队列中的消息确实已经处理完毕,而不是刚被Pod取走:
kind: HorizontalPodAutoscaler apiVersion: autoscaling/v2beta1 metadata: name: hpa-name spec: scaleTargetRef: apiVersion: apps/v1beta1 kind: Deployment name: deployment-name minReplicas: 1 maxReplicas: 50 behavior: scaleDown: stabilizationWindowSeconds: 300 # 等待5分钟再缩容 metrics: - type: External external: metricName: sqs-visible-messages targetAverageValue: 1
这个方案适合那些不想修改指标配置,只想通过参数调优解决问题的场景。
4. 结合Pod的CPU/内存指标做混合扩缩容
你还可以把SQS的消息数指标和Pod的CPU、内存使用率结合起来,做混合模式的HPA扩缩容:
kind: HorizontalPodAutoscaler apiVersion: autoscaling/v2beta1 metadata: name: hpa-name spec: scaleTargetRef: apiVersion: apps/v1beta1 kind: Deployment name: deployment-name minReplicas: 1 maxReplicas: 50 metrics: - type: Resource resource: name: cpu targetAverageUtilization: 70 - type: External external: metricName: sqs-visible-messages targetAverageValue: 1
这样,HPA会同时参考CPU使用率和队列消息数:当队列消息增多时触发扩容,当CPU使用率下降且队列消息很少时再触发缩容,避免因为消息刚被取走就误缩容。
内容的提问来源于stack exchange,提问作者Chakradar Raju




