AWS DynamoDB 完整教程:表设计、分区键选择、数据读写与计费方式

AWS DynamoDB 教程

Amazon DynamoDB 是 AWS 提供的全托管 NoSQL 数据库服务,单个表可以扩展到每秒数百万次请求,读写延迟稳定在个位数毫秒级别。它没有服务器需要管理,不需要手动配置主从复制或处理分区,所有基础设施层面的运维由 AWS 负责。

初次接触 DynamoDB 的团队最常见的困惑是数据模型设计和计费与关系型数据库完全不同。
设计不当的表在小流量下看不出问题,流量一旦上来,热分区限流和意外的 GSI 写入成本就会同时出现。

DynamoDB 是什么,什么场景适合用它

DynamoDB 是键值(Key-Value)和文档型 NoSQL 数据库,不需要预先定义 Schema,每个项目(Item)可以有不同的属性集合。它和关系型数据库(RDS)的本质差别不在于功能多少,而在于读写模式的设计方向:DynamoDB 要求在建表时就想清楚应用会用什么方式访问数据,然后围绕访问模式设计键结构;RDS 的表结构可以先建好,之后用 SQL 灵活查询任意维度。

DynamoDB 适合以下场景:

  • 访问模式明确且以键查询为主(通过用户 ID 查用户信息、通过订单 ID 查订单详情)
  • 需要应对流量波动,无法提前预测峰值
  • 和 Lambda 配合构建 Serverless 架构,不需要维护数据库服务器
  • 需要毫秒级延迟的高并发读写(游戏排行榜、会话存储、实时计数)
  • 数据没有复杂的多表关联查询需求

不适合 DynamoDB 的场景:业务需要大量 JOIN 操作、复杂多条件过滤查询、或者有严格 ACID 事务要求的核心财务系统。这类需求选 RDS 更合适,关于 RDS 的完整配置说明可以参考 AWS RDS数据库 教程。

DynamoDB 提供永久免费额度:每月 25GB 存储、25 个写入容量单元(WCU)和 25 个读取容量单元(RCU),可以处理约 2 亿次请求,小型项目或开发测试环境完全够用。

核心概念:表、项目、分区键与排序键

表和项目的结构

DynamoDB 的数据组织方式和关系型数据库有对应关系,但不完全相同。表(Table)是最高层的容器,对应关系型数据库的表;项目(Item)是表中的每一条记录,对应行;属性(Attribute)是项目中的每个字段,对应列。不同的是,DynamoDB 的项目不需要有相同的属性集合——同一张表里,一个项目可以有 5 个属性,另一个项目可以有 20 个属性,互不影响。唯一必须存在的属性是主键。

分区键:决定数据存储位置

主键有两种形式。简单主键只由分区键(Partition Key,也叫 Hash Key)一个属性构成,这个属性的值必须在整张表里唯一。复合主键由分区键排序键(Sort Key,也叫 Range Key)两个属性共同构成,分区键相同的项目可以共存,只要排序键不同。

分区键的工作方式是:DynamoDB 对分区键的值做哈希运算,根据结果决定这个项目存储到哪个物理分区。这意味着分区键相同的所有项目会存储在同一个物理分区,它们共享这个分区的读写吞吐量配额。

分区键设计是整个 DynamoDB 架构中最关键的决定。 好的分区键需要有足够多的唯一值(高基数),让数据均匀分布在多个分区上。如果选了一个基数很低的字段做分区键(比如只有”男/女”两个值的性别字段),所有数据会集中在极少数分区,产生热分区,导致限流,即使整体表的吞吐量配额充足也无济于事。用户 ID、订单 ID、设备 ID 这类本身就有大量唯一值的字段,是分区键的理想选择。

排序键:在同一分区内做范围查询

复合主键中的排序键,让同一分区键下的多个项目可以通过范围条件查询。同一个分区键下的项目,DynamoDB 按排序键的值排序存储,Query 操作可以对排序键做 =、<、>、BETWEEN、begins_with 等条件过滤。

举一个典型例子:用户订单表,以 userId 为分区键,以 orderDate 为排序键。这个设计可以高效地查询某个用户的所有订单(只指定分区键),也可以查询某个用户某段时间内的订单(分区键 + 排序键的范围条件),同时所有属于同一用户的订单存储在同一物理分区,单次 Query 可以连续读取。

创建表与基本数据操作

用 AWS CLI 创建表

以下命令创建一个用户订单表,复合主键由 userId(分区键)和 orderDate(排序键)构成:

aws dynamodb create-table \

  –table-name UserOrders \

  –attribute-definitions \

    AttributeName=userId,AttributeType=S \

    AttributeName=orderDate,AttributeType=S \

  –key-schema \

    AttributeName=userId,KeyType=HASH \

    AttributeName=orderDate,KeyType=RANGE \

  –billing-mode PAY_PER_REQUEST

PAY_PER_REQUEST 表示按需模式,不需要预设容量,适合初期使用。AttributeType=S 表示字符串类型,DynamoDB 支持字符串(S)、数字(N)和二进制(B)三种主键属性类型。

写入和读取项目

写入一条订单记录:

aws dynamodb put-item \

  –table-name UserOrders \

  –item ‘{

    “userId”: {“S”: “user-001”},

    “orderDate”: {“S”: “2026-07-01T10:30:00Z”},

    “orderId”: {“S”: “order-abc123”},

    “amount”: {“N”: “299.99”},

    “status”: {“S”: “completed”}

  }’

按分区键查询某用户的所有订单:

aws dynamodb query \

  –table-name UserOrders \

  –key-condition-expression “userId = :uid” \

  –expression-attribute-values ‘{“:uid”: {“S”: “user-001”}}’

查询某用户 2026 年 6 月之后的所有订单:

aws dynamodb query \

  –table-name UserOrders \

  –key-condition-expression “userId = :uid AND orderDate >= :date” \

  –expression-attribute-values ‘{

    “:uid”: {“S”: “user-001”},

    “:date”: {“S”: “2026-06-01T00:00:00Z”}

  }’

Query 和 Scan 的根本差别

DynamoDB 有两种读取数据的操作:Query 和 Scan。这两者的成本差距极大,是设计访问模式时最需要理解的一点。

Query 必须指定分区键值,DynamoDB 直接定位到对应分区读取数据,只消耗实际返回项目的读取容量。

Scan 会读取整张表(或整个 GSI),逐一检查每个项目是否满足过滤条件,计费按照扫描到的所有项目而非过滤后返回的项目计算。一张有 5000 万条记录的表,Scan 一次要读取所有 5000 万条,成本和实际需要的数据量完全不成比例。生产环境中应该完全避免 Scan,任何需要 Scan 的查询模式都意味着表设计需要重新考虑。

Filter Expression 是另一个容易误解的地方。Filter 条件虽然可以在返回结果前过滤掉不需要的项目,但过滤是在 DynamoDB 读取数据之后发生的——读取 100 个项目但过滤掉 90 个,计费依然是 100 个项目的读取容量,不是 10 个。Filter Expression 只能减少网络传输量,不能减少读取成本。如果大量依赖 Filter 来缩小结果集,说明表的键设计需要调整。

全局二级索引(GSI):扩展查询能力与成本影响

什么是 GSI

DynamoDB 的 Query 操作只能通过主键(分区键 + 排序键)查询,无法直接按其他属性过滤。如果需要按 status(订单状态)查询所有已完成的订单,原始表结构无法高效支持。这时可以创建全局二级索引(GSI),为其他属性建立独立的索引表,使用 GSI 的分区键和排序键做查询。

GSI 对写入成本的影响

这是 DynamoDB 账单中最常见的意外来源。每个 GSI 会独立维护一份被索引属性的数据副本,每次向基表写入一条项目,所有相关 GSI 也会自动同步这条项目,每个 GSI 的写入单独计费。

一张表有 5 个 GSI,使用 ALL 投影(将表中所有属性都复制到 GSI):

  • 写入 1 个项目 = 1 次基表写入 + 5 次 GSI 写入 = 6 倍写入成本
  • 存储空间 = 1 份基表数据 + 5 份 GSI 数据 = 6 倍存储成本

每月 1 亿次写入,按需模式下:没有 GSI 时成本 $125;5 个 GSI 时成本 $750。仅 GSI 设计这一个决定,让成本增加了 5 倍。

减少 GSI 成本的几种方法:用 KEYS_ONLY 投影(只保留主键属性)或 INCLUDE 投影(只保留必要的属性)替代 ALL 投影;定期检查是否有使用率极低的 GSI,开发阶段创建的测试 GSI 如果没有及时删除,即使没有查询流量也会持续产生写入和存储费用;在 GSI 之前先评估是否可以通过复合排序键的设计来支持查询需求,减少 GSI 总数量。

两种容量模式:按需 vs 预置

按需模式

按需模式(On-Demand)不需要预设任何容量,DynamoDB 自动根据流量扩缩,每次读写操作独立计费。2024 年 11 月 AWS 将按需模式价格下调 50%,之后 AWS 官方将按需模式列为大多数工作负载的推荐起点。

2026 年按需模式价格(us-east-1):写入 $1.25/百万次请求,读取 $0.25/百万次请求。按需模式的优势是零容量规划风险——流量突增不会因为配额不足而限流,新项目不需要估算初始流量。

预置模式

预置模式(Provisioned)需要提前指定每秒的读取容量单元(RCU)和写入容量单元(WCU),按预置的容量小时计费,不管实际是否用满。一个 WCU 对应每秒 1 次最大 1KB 的写入,一个 RCU 对应每秒 1 次最大 4KB 的强一致性读取(最终一致性读取每个 RCU 可以执行 2 次)。

同等负载下,预置模式比按需模式便宜 5–7 倍。以每秒 100 次写入、每次 1KB 为例:按需模式每月约 $324,预置模式(100 WCU 包年)每月约 $47。

对比项按需模式预置模式
容量规划无需规划需要提前设定 WCU/RCU
价格约 5–7 倍于预置更低,适合稳定流量
流量突增自动处理超出配额会限流
适合场景新项目、流量不可预测稳定业务,流量可预测
最大折扣Database Savings Plans 最高 18%预留容量最高 77%

切换时机的判断: 新项目上线后,观察 2–4 周的流量数据,确认流量模式稳定后评估是否切换到预置模式。实际操作中,很多团队在按需模式启动后便忘记重新评估,长期以按需模式运行一个流量已经完全可预测的表,每月多付 5–7 倍费用。在控制台设置日历提醒,上线 30 天后检查一次容量模式是一个值得养成的习惯。

2025 年 12 月 AWS 推出 Database Savings Plans,通过承诺每小时最低消费金额,在不绑定具体实例类型的情况下,按需模式最高获得 18% 折扣,预置模式最高 12%,同时覆盖其他 9 种 AWS 数据库服务。关于 AWS 折扣承诺机制的完整判断,可以参考 亚马逊云服务器价格 的分析框架。

常见使用场景

会话存储(Session Store)

Session 数据需要低延迟读写、支持过期自动删除,DynamoDB 的 TTL(Time To Live)功能非常契合:为每个 Session 项目设置 expiresAt 属性(Unix 时间戳),DynamoDB 自动在到期后删除该项目,删除操作不消耗任何读写容量。Python 示例:

import boto3

import time

dynamodb = boto3.resource(‘dynamodb’)

table = dynamodb.Table(‘Sessions’)

# 创建 Session,设置 TTL 为 24 小时后过期

table.put_item(Item={

    ‘sessionId’: ‘sess-abc123’,

    ‘userId’: ‘user-001’,

    ‘data’: {‘cart’: [‘item-1’, ‘item-2’]},

    ‘expiresAt’: int(time.time()) + 86400  # 24 小时后

})

# 读取 Session

response = table.get_item(Key={‘sessionId’: ‘sess-abc123’})

session = response.get(‘Item’)

和 Lambda 配合的 Serverless 架构

DynamoDB 和 Lambda 的组合是 AWS Serverless 架构的核心之一:Lambda 处理业务逻辑,DynamoDB 持久化数据,两者都按实际用量计费,空闲时几乎不产生费用,适合流量不稳定的业务。关于 Lambda 的事件触发配置和 Python SDK 调用方式,可以参考 AWS Lambda 完整教程。

游戏排行榜

有序集合(Sorted Set)类查询可以用 DynamoDB 的复合主键实现:以游戏 ID 为分区键,以分数(取反使高分排前)为排序键,就可以用 Query 按分区键查询某个游戏的榜单,并通过排序键范围获取 Top N 玩家,不需要全表扫描或手动排序。

配合 ElastiCache 降低读取成本

对于读多写少的场景(商品详情、用户资料),可以在 DynamoDB 前置一层 ElastiCache 缓存。高频请求直接从内存返回,大幅减少 DynamoDB 的读取容量消耗。ElastiCache 的详细配置方式可以参考 AWS ElastiCache 完整教程。

计费构成与容易被忽视的成本

DynamoDB 账单由四个部分构成:吞吐量费用(最大头)、存储费用、备份费用和可选附加功能费用。吞吐量是大多数团队账单的主要来源,而 GSI 是吞吐量费用最大的隐性放大器。

存储费用: 标准存储类 $0.25/GB-月,Standard-IA(低频访问)$0.10/GB-月,但 Standard-IA 的读写单价更高,只适合读写极少、以存储为主的冷数据表。每个项目额外包含 100 字节的系统元数据开销计入存储费用,单个项目大小上限为 400KB。

备份费用: 持续备份(PITR)$0.20/GB-月,按需快照备份 $0.10/GB-月。持续备份提供 35 天内任意时间点恢复,对有数据恢复需求的生产表是值得的投入。

Global Tables(全球表): 跨区域复制,写入费用按 1.5 倍计算(每次写入产生 1.5 个复制写入单元),两个区域时总写入成本约 2.5 倍,三个区域约 4 倍。跨区域数据也会产生传输费用。

热分区限流: 这不是直接的成本项,但是性能问题的常见来源。即使整体表的吞吐量配额充足,集中在少数分区键上的流量(热分区)会因为单分区的物理限制而触发限流,表现为 ProvisionedThroughputExceededException。解决方式是重新设计分区键,确保流量均匀分散到多个分区。

账号开通与代理充值

使用 DynamoDB 需要有效的 AWS 账号,DynamoDB 本身没有配额申请门槛,创建表和开始使用都不需要额外审批。对于长期运行 DynamoDB 业务、月均消耗超过 $200 的团队,通过 AWS 代理商 渠道充值可以享受代理专属折扣(低至 7 折),配合 Database Savings Plans 或预留容量折扣叠加使用,年度实际成本明显低于官网直充。付款支持 USDT 和对公转账,适合没有海外信用卡或需要企业对公结算的团队,账号免实名、免绑卡,1 分钟极速交付。

AWS 代理

滚动至顶部