人人都能学编程
English 开始学习
专项 · 云与 SRE第 4 课 / 共 5 课免费阅读

自动扩缩容 · 云与可靠性

流量上涨时服务怎么扩容,流量下降时又怎么缩容?

课程目录

为什么需要它

流量不是一条直线:午饭时间、一场促销、社交媒体上的一次提及,都可能让它翻好几倍。全天按峰值配服务器很浪费钱;配少了网站又会变慢甚至挂掉。自动扩缩容会自动调整副本数量,理解它的规则,你就知道该怎么配置它,以及它为什么有时会出乎你的意料。

直觉理解

Kubernetes 的水平 Pod 自动扩缩器(HPA)用的是一个公式(见它的官方文档):

期望副本数 = ceil( 当前副本数 × 当前指标 / 目标指标 )

CPU 目标是 50% 时:4 个 Pod 平均 CPU 80% → ceil(4 × 80 / 50) = ceil(6.4) = 7 个 Pod。负载分摊到更多的 Pod 上,每个 Pod 就更接近 50%。

有两道护栏让它保持理智:

  • 上下限:永远不少于 min,不多于 max 个副本。上限保护你的账单和数据库。
  • 容差:如果比值 当前 / 目标 和 1 相差不到 10%(HPA 的默认值),就什么都不做。没有它,微小的波动会让 Pod 整天加了又减(「抖动」)。

扩容需要时间:新 Pod 要启动,还要通过就绪探针。所以目标值通常远低于 100%:留出的余量用来扛住新 Pod 启动期间上涨的流量。

定义

自动扩缩容

Automatically changing the number of copies of a service based on a metric such as CPU or requests per second.
根据 CPU 或每秒请求数等指标,自动改变服务的副本数量。

目标利用率

The level of a metric the autoscaler tries to keep each copy at, such as 50% CPU.
自动扩缩器努力让每个副本保持的指标水平,比如 50% 的 CPU。

抖动

Scaling up and down repeatedly because of small changes. A tolerance or a cool-down prevents it.
因为微小的变化反复扩容又缩容。容差或冷却时间可以防止它。

示例

负载高于目标 → 更多 Pod;低于目标 → 更少。

import math

def desired(current, cpu, target):
    return math.ceil(current * cpu / target)

print(desired(4, 80, 50))
print(desired(4, 50, 50))
print(desired(10, 12, 50))
输出
7
4
3
逐步执行
  1. L4向上取整:零点几个 Pod 也需要一个完整的 Pod。
  2. L64 × 80 / 50 = 6.4 → 7。7
  3. L8安静的夜晚:10 × 12 / 50 = 2.4 → 3。3

加上上下限

动手试试

min 和 max 把结果限制在范围内。

import math

def desired(current, cpu, target):
    return math.ceil(current * cpu / target)

def bounded(current, cpu, target, lo, hi):
    return max(lo, min(hi, desired(current, cpu, target)))

print(bounded(4, 300, 50, 2, 10))
print(bounded(4, 5, 50, 2, 10))
输出
10
2
逐步执行
  1. L7先用 hi 封顶,再保证不低于 lo。
  2. L9一次尖峰要 24 个 Pod;上限只允许 10 个。10
  3. L10几乎空闲时只要 1 个;为了安全至少保留 2 个。2

常见错误

没有上限

一个吃 CPU 的 bug 或一次攻击,会把你扩到几百个 Pod,账单也随之暴涨。一定要设置上限。

目标值接近 100%

新 Pod 启动需要时间。没有余量的话,等待期间现有的 Pod 会被压垮。

扩容扩错了地方

如果瓶颈在数据库,再多的 Web Pod 只会给它发更多的查询。先找到真正的瓶颈。

小测验

1. 这段代码会输出什么?

import math

def desired(current, cpu, target):
    return math.ceil(current * cpu / target)

print(desired(3, 90, 60))
  1. A
    5
  2. B
    4
  3. C
    3
查看答案

答案:A

3 × 90 / 60 = 4.5,向上取整为 5。

2. 为什么自动扩缩器会忽略和目标相差不到 10% 的变化?

  1. A避免因为微小的波动加了又减 Pod
  2. B因为指标总是有 10% 的误差
  3. C为了节省自动扩缩器的内存
查看答案

答案:A

容差区间可以防止抖动。

动手练习

3 道练习,分三层:先预测程序的输出,再按新需求改程序,最后从零写一个。代码在浏览器里运行,提交马上判题。

  1. 预测输出忙碌的早晨

    准确写出它打印的内容。

  2. 改需求别再抖动了

    这个自动扩缩器每有一点点变化就加减 Pod。加上容差:如果 cpu / target 和 1 相差在 10% 以内(0.9 到 1.1,含两端),就保持 current 不变。

  3. 从零写重放一天

    写一个 replay(start, readings, target, lo, hi),返回每次 CPU 读数之后的副本数。对每个读数:

    1. ratio = cpu / target;如果在 0.9 到 1.1 之间,保持当前数量
    2. 否则取 ceil(当前数量 × ratio)
    3. 然后限制在 lo…hi 之间
    replay(2, [50, 90, 300, 10], 50, 2, 8)   # [2, 4, 8, 2]

在互动课里练这一课

打开互动课,这些例子都能直接改、直接运行,练习题提交马上判题。免费开始,不用注册。

互动课按顺序解锁:前面的课还没学,会先带你到课程地图。

本课术语

术语中文英文定义
Autoscaling自动扩缩容Changing the number of copies to match load.
HPAHPA 水平自动扩缩Kubernetes' Horizontal Pod Autoscaler.
Flapping抖动Scaling up and down over and over.