Skip to main content

阿里云 ACK 中使用 cronhpa 计划性弹性伸缩来应对整点秒杀

业务背景

整点秒杀活动背景

跨境电商独立站业务,计划在3月8日零点整点开启85折整点抢券,预计会产生高于平日 2倍 的流量。

业务场景分析

很明显这属于 “整点秒杀” 类型的业务场景

为什么 K8S 自带的 HPA 弹性扩容无法应对爆发性流量?

  1. ​调节滞后性:HPA 指标采集与评估有时间间隔,决策到执行也有延迟,难以及时应对整点秒杀瞬时流量。
  2. 扩容速度限制:Pod 扩容受到集群资源准备、健康检查、镜像拉取等因素影响
  3. ​预测能力不足:HPA 不了解业务模式,无法提前预知整点秒杀流量,错过资源预准备的最佳时机

所以 HPA 更适用于平稳的流量增长带来的扩缩容场景,而 “整点秒杀” 类型的业务场景是瞬时性的突发流量,HPA 根本反应不过来,业务流量直接把容器组负载打满,用户的反应是 ———— 卡卡卡 ————

接下来要引入 阿里云 ACK 的 cronhpa 能力来解决这个问题。

准备条件

  1. 已创建ACK托管集群、ACK Serverless集群
  2. 已通过 kubectl 工具连接集群

CronHPA 基础模板及参数介绍

CronHPA 基于 kubernetes-cronhpa-controller 实现。kubernetes-cronhpa-controller 是一个基于时间的 Pod 水平伸缩 Controller,按照类似 Crontab 的策略定时地对集群进行扩缩容,例如在工作日的业务高峰期自动增加Pod数量,在业务低谷时自动减少Pod数量。

CronHPA 可以作用于任何支持伸缩子资源(Scale Subresource)的Kubernetes对象,例如Deployment、StatefulSet 等。

安装 CronHPA 的组件

  1. 登录容器服务管理控制台,在左侧导航栏选择集群。
  2. 在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择运维管理 > 组件管理。
  3. 单击应用管理页签,找到ack-kubernetes-cronhpa-controller,按照页面提示完成组件的安装。

CronHPA 模板参数说明

apiVersion: autoscaling.alibabacloud.com/v1beta1
kind: CronHorizontalPodAutoscaler
metadata:
labels:
controller-tools.k8s.io: "1.0"
name: cronhpa-sample
namespace: default
spec:
scaleTargetRef: # 指定扩缩容的对象
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment-basic
excludeDates: # 需要跳过不执行的时间段,最小单位为天。
# exclude November 15th # 例如:11月15日不运行任务
- "* * * 15 11 *"
# exclude every Friday # 例如:每周五不运行任务
- "* * * * * 5"
jobs:
- name: "scale-down" # 在 job 中是唯一的,通过 job 来区分不同的任务用途
schedule: "30 */1 * * * *" # 秒 分 时 日 月 周
targetSize: 1 # 目标副本数量
- name: "scale-up"
schedule: "0 */1 * * * *"
targetSize: 3
runOnce: false # 设置为true时,任务将只执行一次,第一次执行完则退出(Exit)

实现 CronHPA 与 HPA 的协同 的部署案例

由于 CronHPA 和 HPA 两者无法相互感知,如果您的应用使用 YAML 同时配置了 CronHPA 和 HPA,可能会出现两种配置独立工作,后执行操作覆盖了先执行操作的现象。

ACK 提供了 CronHPA 兼容 HPA 的方案——当检测到两者同时存在时,通过将 HPA 作为 CronHPA 的 scaleTargetRef,CronHPA 可以明确知晓并综合考虑 CronHPA 任务当前的目标副本数, HPA 中的 minReplicas、 maxReplicas 和 desiredReplicas 数值,以及 HPA 中 scaleTargetRef 对象的当前副本数。

一句话概括就是:CronHPA 不会直接调整 Deployment 的副本数目,而是通过 HPA 来修改 Deployment配置,避免HPA 和 CronHPA 发生冲突。

HPA

以下策略定义了一个应用的常规 HPA 策略:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
labels:
app: shopping-mall
app.kubernetes.io/managed-by: Helm
name: shopping-mall
namespace: mall
spec:
maxReplicas: 100 # 最大维持副本数量
metrics:
- resource:
name: cpu
target:
averageUtilization: 50
type: Utilization
type: Resource
minReplicas: 10 # 最小维持副本数量
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: shopping-mall

CronHPA

以下策略定义了 CronHPA 以 HPA 为操作对象(即协同):

  • 在 3月7日晚上 23点(提前一小时)讲负载能力扩容两倍
  • 在 3月8日凌晨 3点回收资源
apiVersion: autoscaling.alibabacloud.com/v1beta1
kind: CronHorizontalPodAutoscaler
metadata:
name: shopping-mall
namespace: mall
spec:
jobs:
- name: scale-up
runOnce: false
schedule: 0 0 23 7 3 * # 3月7日23点执行扩容任务,副本数扩容到平日的两倍数量
targetSize: 20
runOnce: true # true 这是一个一次性的任务
- name: scale-down # 3月8日凌晨执行缩容任务,副本数量恢复
runOnce: false
schedule: 0 0 3 8 3 *
targetSize: 10
runOnce: true # true 这是一个一次性的任务
scaleTargetRef:
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
name: shopping-mall # 以 HPA 为操作对象

Prometheus 监控负载情况

3月7日 23点 ~ 3月8日 3点,期间预部署2倍动态资源,仅覆盖4小时,极大程度的节约服务器成本,又应对了整点秒杀流量高峰。

阿里云后台成本

阿里云 弹性容器实例 单价:

覆盖4小时仅使用了 12元。

案例总结

  1. 对于平日常规性的流量峰谷场景,普通的 HPA 就可以完成动态扩容缩容任务
  2. 但是对于电商整点秒杀场景:用计划性弹性容器实例预部署,既能很好的应对已知的流量高峰,又能很好的解决用云成本
  3. 如果应用同时部署了 HPA 和 CronHPA,那么必须配置两者协同来防止相互覆盖的问题

参考文档