常见限流错误码解析:ThrottlingException 等
限流报错,说白了就是 KMS 跟你说「慢点,扛不住了」。我自己排查故障时,最先看的就是错误码。不同错误码背后是不同限流策略,搞混了会走弯路。这一章我把常见的限流错误码梳理清楚,再讲讲实战怎么处理它们。
限流错误码全家桶
KMS 限流相关的错误码有好几个,但最核心的就那三四个。我整理了一张表,方便你对照排查:
| 错误码 | HTTP 状态码 | 含义 | 常见触发场景 | 应对策略 |
|---|---|---|---|---|
| ThrottlingException | 429 | 请求速率超过账户级或 API 级限制 | 批量加密、频繁 CreateKey | 等待 Retry-After 后重试,使用退避算法 |
| LimitExceededException | 400 | 资源数达到上限(如密钥数) | 创建第 1000 个 CMK | 删除旧资源或申请增加配额 |
| TooManyRequestsException | 429 | 并发请求过多(某些 SDK 独有) | 高频调用 Decrypt | 减少并发数,增加本地缓存 |
| ServiceUnavailable (503) | 503 | 服务过载,临时性限流 | 突增流量 | 重试 + 退避,考虑熔断 |
| RequestLimitExceeded | 429 | (极少见)API 调用速率超限 | 批量调用 ListKeys | 与 ThrottlingException 同处理 |
ThrottlingException 深度解析
这是限流故障里出现频率最高的错误码,没有之一。我最早遇到它是在一个日志加密项目里,批量加密时瞬间并发拉满,结果一大片错误飞回来了。嗯,当时还是有点慌的。
为什么它会频繁出现?因为 KMS 的限流分两层:账户级和API 级。账户级就是整个账号每秒最多处理多少请求,API 级则是每个接口(比如 GenerateDataKey)有自己的配额。ThrottlingException 通常指的是账户级限流。
举个实战场景:你用 KMS::Encrypt 连续加密 1000 个数据块,每个调用单独发送。假设账户级限流是 500 QPS,那你第 1000 个请求极大概率收到 ThrottlingException。这时候 SDK 会帮你自动重试吗?不一定。有些语言 SDK 默认只重试 3 次,而且重试逻辑可能没考虑抖动。我们来看一段代码:
import boto3
from botocore.config import Config
config = Config(
retries={'max_attempts': 5, 'mode': 'adaptive'}
)
kms = boto3.client('kms', config=config)
try:
response = kms.encrypt(
KeyId='alias/my-key',
Plaintext=b'sensitive data'
)
except ClientError as e:
if e.response['Error']['Code'] == 'ThrottlingException':
# 手动读取 Retry-After
retry_after = e.response['ResponseMetadata']['HTTPHeaders'].get('retry-after')
if retry_after:
time.sleep(int(retry_after) + random.random() * 0.1)
raise
其他常见限流错误码对比
光知道 ThrottlingException 还不够,我遇到过很多同学把 LimitExceededException 当限流处理,结果无限重试也没用。为什么?因为这是配额问题,不是速率问题。
- LimitExceededException —— 你创建了太多密钥(默认可创建 1000 个 CMK)。处理方式是删密钥或提工单加配额,重试没有任何意义。
- TooManyRequestsException —— 一些 SDK 把并发层限流单独拎出来。比如你用 100 个线程同时调用 Decrypt,即使总 QPS 不超也可能触发这个。解决方法是改用连接池或控制并发数。
- ServiceUnavailable —— 这个错误码有时不是限流,是服务真的宕了。但 KMS 限流严重时也会返回 503。我一般和 429 一样处理:退避重试,但增加熔断逻辑(比如连续 3 次 503 就暂停 10 秒)。
错误码背后的限流维度
KMS 限流不是「一刀切」,它分几个维度。我画了一张流程图,帮你理解收到错误后该怎么定位:
实战小贴士:错误码处理最佳实践
结合上面的流程,我总结几个实操要点:
- 先区分「限流」和「配额」:Throttling 类错误才退避重试,LimitExceeded 类错误去查 Console 或工单。
- 一定用指数退避 + 随机抖动:不能只写
time.sleep(1),那是自杀式重试。我推荐底层基数为 2,上限 30 秒。 - 读取 Retry-After 头:很多云厂商在这个头里告诉你具体等多久。我见过一个项目,错误码是 ThrottlingException,响应头里回了 5 秒,但客户端硬等了 30 秒,白白浪费时间。
- 加业务层面的降级:限流频繁时可以考虑本地缓存结果(比如 Decrypt 结果缓存 5 分钟),减少对 KMS 的直接调用。
- 监控限流指标:在 CloudWatch 里设置
ThrottledCount指标告警,限流超过阈值时自动发通知。我自己习惯每 5 分钟检查一次,如果连续两次阈值超过 10%,就启动降级。
一句话总结:
收到 429/503 → 解析错误码 → 是限流类 → 读 Retry-After → 指数退避+抖动重试;
是 LimitExceeded → 查资源数、删密钥或加配额;
其他错误 → 按对应文档处理。