DynamoDB 限制与配额,对照真实服务逐项核实
DynamoDB 有哪些限制?
一个项目最高 400 KB,一个分区键最高 2,048 字节,一个排序键最高 1,024 字节。 一次批量写入最多 25 个项目,一次批量读取最多 100 个键,一次事务最多 100 个 操作。一张表最多可以有 20 个全局二级索引和 5 个本地二级索引。本页上的每一个 数字,都是通过向 Amazon DynamoDB 实际发送请求、并读取它的回应而确定的。
这些数字是如何确定的
AWS 公布其配额时并不附带证据,这通常没什么问题 —— 直到某个数字要撑起一个设 计决策,而你想知道它指的到底是 400,000 字节还是 409,600 字节,它是否把你的 属性名也算进去,以及当你越界时服务到底会说什么。
所以我们亲自探测了它们。对于下方第一张表里的每一个限制,我们都构造了一个
恰好停在文档所写数值上的请求,发送到 us-east-1 的真实服务;然后再发一个
比它多一个单位的请求。前者必须被接受,后者必须被拒绝 —— 正是这一对请求定位
了真正的边界,而不是照搬文档的说法。最后一列中的拒绝消息是服务自己给出的原
话,原样捕获,从未重新敲打过。
有四行只能从拒绝那一侧确定。它们是 CreateTable 的限制,其接受侧意味着要建
一张带二十个索引的表,并等待每一个都变为 active,才能得到一个拒绝消息里本就
直接写明的数字。如何确定 这一列说明了每一行属于哪一种,它不是装饰。
已验证的限制
| 限制 | 值 | 如何确定 | 越界时服务返回什么 |
|---|---|---|---|
| 最大项目大小 | 409,600 字节 | 在 409,600 时被接受,在 409,601 时被拒绝 | ValidationException: Item size has exceeded the maximum allowed size |
| 最大分区键值 | 2,048 字节 | 在 2,048 时被接受,在 2,049 时被拒绝 | ValidationException: One or more parameter values were invalid: Size of hashkey has exceeded the maximum size limit of2048 bytes |
| 最大排序键值 | 1,024 字节 | 在 1,024 时被接受,在 1,025 时被拒绝 | ValidationException: One or more parameter values were invalid: Aggregated size of all range keys has exceeded the size limit of 1024 bytes |
| 最大嵌套深度 | 32 层 | 在 32 时被接受,在 33 时被拒绝 | ValidationException: 1 validation error detected: Nesting Levels have exceeded supported limits: Attributes in the item have nested levels beyond supported limit |
| 最大表达式长度 | 4,096 字节 | 在 4,096 时被接受,在 4,097 时被拒绝 | ValidationException: 1 validation error detected: Invalid ConditionExpression: Expression size has exceeded the maximum allowed size; |
| 每次 BatchWriteItem 的最大项目数 | 25 个项目 | 在 25 时被接受,在 26 时被拒绝 | ValidationException: 1 validation error detected: Value '<your request>' at 'requestItems' failed to satisfy constraint: Map value must satisfy constraint: [Member must have length less than or equal to 25, Member must have length greater than or equal to 1] |
| 每次 BatchGetItem 的最大键数 | 100 个项目 | 在 100 时被接受,在 101 时被拒绝 | ValidationException: 1 validation error detected: Value at 'RequestItems.<table-name>.member.Keys' failed to satisfy constraint: Member must have length less than or equal to 100 |
| 每次 TransactWriteItems 的最大操作数 | 100 个项目 | 在 100 时被接受,在 101 时被拒绝 | ValidationException: 1 validation error detected: Value '<your request>' at 'transactItems' failed to satisfy constraint: Member must have length less than or equal to 100 |
| 每张表的全局二级索引数 | 20 | 仅拒绝侧 | ValidationException: One or more parameter values were invalid: GlobalSecondaryIndex count exceeds the per-table limit of 20 |
| 每张表的本地二级索引数 | 5 | 仅拒绝侧 | ValidationException: One or more parameter values were invalid: Number of LocalSecondaryIndexes exceeds per-table limit of 5 |
| 每个索引投影的非键属性数 | 20 | 仅拒绝侧 | ValidationException: 1 validation error detected: Value '<your request>' at 'globalSecondaryIndexes.1.member.projection.nonKeyAttributes' failed to satisfy constraint: Member must have length less than or equal to 20 |
| 每张表投影的非键属性数 | 100 | 仅拒绝侧 | ValidationException: One or more parameter values were invalid: Number of projected attributes in all indexes exceeds limit of 100, number of projected attributes:120 |
环境:Amazon DynamoDB,真实服务,us-east-1,于 2026-08-27 用 AWS SDK for
JavaScript v3 探测。
探测揭示了什么
400 KB 指的是 409,600 字节,而且它把你的属性名也算进去。 一个恰好测得 409,600 字节的项目被接受了;409,601 字节的被拒绝了。这项测量把每一个属性名 和每一个值的 UTF-8 长度都算了进去,这与我们的 项目大小计算器所实现的计算方式完全 一致 —— 探测脚本正是用那个库来构建负载的,所以两者是通过构造上的一致来对齐 的,而不是靠断言。这个限制背后更深层的建模问题,有它自己的一篇指南: DynamoDB 项目大小限制。
大家常引用的投影属性限制其实引错了。 AWS 的
配额页面
只记载了一个数字 —— “up to 100 attributes combined for all of a table's local
and global secondary indexes” —— 却从未提到每个索引各自的上限。其实是有
的,而且是 20。一次向单个索引投影 21 个非键属性的 CreateTable 会被拒
绝,此时每表总数远没有接近 100。这个 20 是有文档记载的,只不过只出现在 API
参考的
Projection
页面里,作为一个数组成员约束:“Maximum number of 20 items”。如果你只依据配
额页面来规划一个索引,API 会拒绝一个配额页面告诉你没问题的 schema。上表中同
时列出了这两个数字,并各自附上了能证明它的拒绝消息。
其中两条消息里带着 AWS 自己的拼写错误,这里原样保留,而不是悄悄改正 ——
maximum size limit of2048 bytes 缺了一个空格,number of projected attributes:120 也缺了一个。如果你要在日志里 grep 这些字符串,请照着服务实
际发出的样子 grep,而不是照着读起来通顺的样子。
排序键是按聚合方式测量的。 排序键的拒绝消息写的是 “Aggregated size of all range keys”,而不是 “the sort key”,因为同样的 1,024 字节预算,覆盖的 是这张表以及该项目所落入的每一个本地二级索引各自的排序键。
1 MB 的分页限制,它什么错误都不会抛
上面的每一个限制都会通过拒绝你来宣告自己的存在。而 Query 和 Scan 的分页限制
不会。越过它,DynamoDB 只会返回一个较短的页和一个 LastEvaluatedKey,没有
错误,也没有警告 —— 这就是为什么 “我的 Scan 只返回了表的一部分” 会是一个如
此常见的意外,也是为什么分页不是可选项。
这也意味着没有错误消息可以引用,所以我们改为测量它,而不是激发它:
在每个项目 1,000 字节时,一页容纳了 1,029 个项目并返回了一个
LastEvaluatedKey —— 也就是 1,029,000 字节的项目数据,第 1,030 个项目留给
了下一次请求。在每个项目 5,000 字节时,一页容纳了 208 个项目并返回
了一个 LastEvaluatedKey —— 也就是 1,040,000 字节的项目数据,第 209 个项
目留给了下一次请求。
两页都没有装满 1 MiB 的项目数据 —— 第一页差了大约 19,576 字节。所以分页预 算对每个项目收取的开销,要比项目自身的字节数更多。
两次不同项目大小的探测就足以钉死这个数字。把一页看作
items × (item bytes + per-item overhead) ≤ budget,只有 7 种整字节开
销同时符合这两次测量结果,而其中恰好只有一种能让预算落在一个整齐的二进制
兆字节上:每个项目 19 字节的开销,此时预算落在 1,048,551 到 1,048,971
字节之间 —— 这个区间恰好包含 1,048,576。DynamoDB 的 “1 MB” 正如它自己
的配额页面所说的那样,是二进制含义,而且它既要花在项目字节上,也 要花在
每项目开销上。请为每个项目预留大约 19 字节的这部分开销。
我们没有探测的配额
下面这些限制是引自 AWS,而不是我们测量出来的。 它们是账户级配额:大多 数可以申请调整,而要触达它们,就意味着要按小时计费地预置吞吐量、创建成千上 万张表,或者承诺购买一年的预留容量。这些都不是探测能做的事,所以我们也不会 把它们包装成探测结果。每一行的出处都是 AWS 的 Amazon DynamoDB 中的配额 页面。
| 配额 | 默认值 | 可调整 | 为什么我们没有探测它 |
|---|---|---|---|
| 每个账户每个区域的表数 | 2,500 | 是 | 创建 2,500 张表,只为看着第 2,501 张失败,会留下一个必须有人去清理的账户。 |
| 每张表的预置吞吐量 | 40,000 RCU 和 40,000 WCU | 是 | 预置 40,000 个单位,无论是否发出过一次请求,都会按小时计费。 |
| 每个账户的预置吞吐量 | 80,000 RCU 和 80,000 WCU | 是 | 同样的理由,还要翻倍 —— 而且它改变的是一个账户级的设置。 |
| 每张表的按需吞吐量 | 40,000 RRU 和 40,000 WRU | 是 | 要触达它,意味着要持续维持每秒 40,000 个请求,这是一场带账单的负载测试。 |
| 每个账户的活跃预留容量 | 1,000,000 个容量单位 | 是 | 预留容量是一年期的购买承诺,不是探测能做的事。 |
| 表大小 | 没有实际限制 | — | AWS 说明表在项目数和字节数上都不受限制;没有边界可以去找。 |
你应该围绕哪些限制来设计
这些限制里的大多数你永远不会碰到。真正会左右实际设计的只有以下这几个:
- 每个项目 400 KB 是一个建模约束,而不是一个配额。一个逼近它的项目,通 常是一个以内嵌列表存储的、无界的一对多关系。参见 项目大小限制。
- 1 MB 的分页限制支配着你写的每一个 Query 和 Scan。忽略
LastEvaluatedKey的代码,会在你的数据超出一页的那天悄悄出错。 - 批量写入 25 个项目、批量读取 100 个,塑造着你的批量加载循环。参见 批处理操作。
- 每次事务 100 个操作,是大家在试图让 DynamoDB 表现得像关系型数据库时 常常撞上的那一个。参见事务。
- 20 个 GSI、5 个 LSI、100 个投影属性,对访问模式设计的制约,比吞吐量 配额要频繁得多,而且 LSI 的数量在建表那一刻就已经固定。参见 索引投影和 GSI vs LSI。
上面引用的大多数拒绝消息,在 DynamoDB 错误下也都有自己
的一篇页面,附带能重现每一个的请求。四个 CreateTable 的拒绝消息没有 ——
它们是专门为本页捕获的。
如果想在不实际写入的情况下,对照 400 KB 这条线检查单个项目, 项目大小计算器可以直接在你的浏览器 里运行。如果想查看你自己表里的项目,DynoTable 是一款桌面 DynamoDB 客户端。