进阶阅读约 5 分钟

如何设置 DynamoDB 自动扩缩

DynamoDB 自动扩缩会把一张预置表的读写容量朝着你选定的目标利用率调整,于是你不必再手工调 RCU/WCU,也不必全天候为一份最坏情况的预留付费。本指南是容量这件事里动手的那一半:控制台路径、CLI 命令、这些数字到底该怎么定,以及那些仍会让陡峭尖峰被限流的时间限制。如果你还没选好容量模式,先从按需容量 vs 预置容量开始——自动扩缩只适用于预置模式。

如何在 DynamoDB 表上启用自动扩缩?

在控制台里:打开你的表,进入 Additional settingsRead/write capacityEdit,选择 Provisioned,再为读容量、写容量或两者把 Auto scaling 设为 On,并给每一项设定最小值、最大值和目标利用率(可在 20% 到 90% 之间设置)。在 CLI 里,用 aws application-autoscaling 注册一个可扩展目标,再给它附加一条目标跟踪扩缩策略。通过控制台创建的表默认就启用了自动扩缩。

自动扩缩到底做了什么

一条扩缩策略告诉 Application Auto Scaling 把一张表的消耗容量与预置容量之比保持在你的目标利用率附近,并限制在你设定的最小最大容量边界之内。在底层,它会为上下两个边界各创建一个 CloudWatch 告警;当消耗量越过其中之一时,Application Auto Scaling 就发出一次 UpdateTable 调用来移动预置容量。

在动手设置之前,有两个结构性事实很重要:

  • 策略既是按表的,也是按 GSI 的。每个全局二级索引都有自己的预置吞吐量,所以每一个都需要自己的策略(或者用控制台里那个“对所有 GSI 使用相同设置”的复选框)。一个扩缩不足的 GSI 会限流基表写入——参见为什么 GSI 会限流基表
  • 控制台创建的表默认就开启;之后添加的 GSI 在构建期间不会扩缩。在一张已有的表上新建的 GSI,在回填期间用的是手动容量——盯住它,直到策略附加上去。

你要接受的时间代价

自动扩缩是被动反应的,而它的反应时间是固定的——AWS 写明告警的数据点数量不可调整:

  • 扩容在消耗容量连续两分钟越过目标之后触发(再加上最多几分钟的 CloudWatch 告警延迟)。
  • 缩容要等到连续 15 个一分钟数据点低于目标。
  • 无论由哪一边触发,随后的 UpdateTable 调用都要花上几分钟才能生效——而在这期间,超过上限的请求都会被限流
DynamoDBApplication AutoScalingCloudWatchTrafficDynamoDBApplication AutoScalingCloudWatchTrafficrequests above the old ceiling throttle until the update landsconsumed > target, minute 1consumed > target, minute 2alarm firesUpdateTable (several minutes)

从越界到拿到新容量之间那约 5 分钟的下限,就是这个功能诚实的边界:自动扩缩吸收的是渐长的流量,而不是跃变的流量。一次在一分钟内把负载翻三倍的限时抢购,不管你的策略怎么配,在预置容量上都会被限流;那种形态需要的是按需容量,它能即时容纳最高达你此前峰值两倍的量(超过两倍、且发生在 30 分钟之内的部分仍会被限流——那是同一套物理规律的它自己的版本)。

在控制台中设置

对一张已有的表(AWS 的步骤):

  1. DynamoDB 控制台 → Tables → 选择那张表。
  2. Additional settings 标签页 → Read/write capacityEdit
  3. Capacity modeProvisioned
  4. Table capacity 下,为读、写或两者把 Auto scaling 切到 On,然后为每一项设定 Minimum capacity unitsMaximum capacity unitsTarget utilization
  5. 可选地把同样的设置应用到每一个 GSI,然后 Save

有一个控制台的限制值得知道:冷却时间在那里没有暴露出来。AWS 自己的文档会把你指向 CLI——“要使用更高级的功能,比如设置缩容和扩容的冷却时间”。

在 CLI 中设置

每个维度两次调用:先注册可扩展目标(最小/最大边界),再附加目标跟踪策略。以下逐字取自 AWS 的 CLI 演练,针对一张表的写容量:

aws application-autoscaling register-scalable-target \
    --service-namespace dynamodb \
    --resource-id "table/TestTable" \
    --scalable-dimension "dynamodb:table:WriteCapacityUnits" \
    --min-capacity 5 \
    --max-capacity 10

策略配置放在一个 JSON 文件里:

{
  "PredefinedMetricSpecification": {
    "PredefinedMetricType": "DynamoDBWriteCapacityUtilization"
  },
  "ScaleOutCooldown": 60,
  "ScaleInCooldown": 60,
  "TargetValue": 50.0
}
aws application-autoscaling put-scaling-policy \
    --service-namespace dynamodb \
    --resource-id "table/TestTable" \
    --scalable-dimension "dynamodb:table:WriteCapacityUnits" \
    --policy-name "MyScalingPolicy" \
    --policy-type "TargetTrackingScaling" \
    --target-tracking-scaling-policy-configuration file://scaling-policy.json

读取,把维度换成 dynamodb:table:ReadCapacityUnits,把指标换成 DynamoDBReadCapacityUtilization。对 GSI,资源 id 变成 table/TestTable/index/test-index,并配上 dynamodb:index:* 那组维度。因此一张带三个 GSI、两个维度都要扩缩的表,需要八对目标/策略——把它写成脚本。

这两个冷却时间在 DynamoDB 上默认都是 0,而且是只有 CLI 才有的旋钮:ScaleOutCooldown 是两次容量提升之间的最小秒数(幅度更大的一次扩容仍会立刻放行),ScaleInCooldown 则挡住下一次降容——不过一次扩容会打断正在走的缩容冷却,而不是等它走完。

怎么定这些数字

目标利用率是一个余量与成本之间的旋钮。当目标是 T% 时,你付的大约是消耗容量的 100/T 倍:70% 的目标在稳定流量之上买到约 1.4 倍余量,50% 的目标买到 2 倍。目标越低,越能不被限流地扛住更陡的增长;目标越高,浪费掉的预留越少。取值范围是 20–90%。

这个旋钮直接连着账单。按当前 us-east-1 的费率(推导过程与 DynamoDB 能自动扩缩吗?相同):预置容量在 100% 利用率下每次请求比按需便宜约 3.46 倍,而盈亏平衡点落在约 29% 的利用率上。自动扩缩的工作就是把真实利用率保持在你的目标附近,所以目标实际上是在替你挑折扣:保持在 70%,预置比按需便宜约 2.4 倍;50% 时约 1.7 倍;低于约 29%,你就该改用按需了。用定价计算器核对你自己工作负载的数字。

最小容量是你的尖峰托底:在自动扩缩需要的那约 5 分钟里,它就是已经在那里的容量。按你必须不被限流地吸收的最陡突发来定它,而不是按平均流量。

最大容量是防失控保护——它给一个 bug、一个疯跑的 Lambda 循环或一次负载测试能让你付的钱设了上限。把它设在你现实峰值之上,并把撞到它当成一次告警,而不是正常运行。

缩容受配额限制。预置容量的降容来自一个令牌桶:每个 UTC 日开始时你有 4 次可用,每小时再攒 1 次(手里最多攥 4 次),每张表每天最多 27 次降容——GSI 的额度是分开的,但一次同时降低表和索引的请求,只要有一边额度不够,整个请求就会被拒绝。自动扩缩那保守的 15 分钟缩容在实践中已经照顾到了这一点,但这也解释了为什么尖峰之后容量是缓慢地一级级降下来的——以及为什么来回震荡的流量到一天结束时会被钉在高于自身平均值的位置上。

在 DynoTable 中操作

给最小值定量、验证目标值,两件事都要从真实数字出发,而不是靠猜:条目有多大、有多少个,以及一次有代表性的读或写实际消耗多少。DynoTable 的表视图会呈现实时的条目数量和表大小,它的查询成本预览会在一条语句运行之前显示它的 RCU 估算——一份容量规划正是用这些数字做出来的。要给单个条目定量,免费的条目大小计算器会算出它的 RCU/WCU 占用。

陷阱与后续步骤

  • 自动扩缩赢不了每分区的物理规律。一个热键即便还有富余容量也照样被限流——参见热分区自适应容量
  • 别忘了 GSI。每个索引都各自扩缩(或各自被限流)。
  • 预留容量只能叠加在预置模式上。如果一个工作负载稳定到自动扩缩几乎不动,那么预留容量(仅限标准表类、预置模式)就是下一档折扣——按需表用不了它。
  • 盯住第一天。在 CloudWatch 里把 ConsumedReadCapacityUnits / ConsumedWriteCapacityUnits 对着预置线看,很快就能知道目标是稳住了还是在震荡。

容量是成本模型的一个维度;你的查询消耗了什么则是另一个——Scan 对比 QuerySQL 扫描成本模型覆盖了那一半。

下载 DynoTable,在你把容量数字定死在表上之前,先读出它真实的大小、条目数量和每次查询的成本。

更新于