1. Important Points#

DynamoDB 是 serverless NoSQL database,适合 key-value / document OLTP workload。它的核心不是“建表后随便查”,而是先确定 access pattern,再设计 partition key、sort key 和 secondary index。

good fit:
    predictable access pattern
    high traffic OLTP
    low latency read/write
    event / session / cart / order state / metadata

not good fit:
    ad-hoc query
    complex join
    heavy analytical query
    frequently changing query dimensions
    large cross-item relational transaction

core principles:
    先设计 access pattern,再设计 table / key / index
    Query 优先,Scan 尽量避免
    partition key 要高基数并且流量均匀
    GSI 是额外写入成本和额外容量面,不是免费的 query helper
    hot key / hot partition 是 DynamoDB 最常见生产问题
    PITR / deletion protection / least privilege 应该默认打开

2. Service Configuration#

table#

Item Recommendation
Table name <env>-<service>-<entity>,例如 prod-order-orders
Primary key 优先 composite key: pk + sk
Billing mode 流量不可预测用 PAY_PER_REQUEST;稳定大流量用 provisioned + auto scaling
Deletion protection production table 默认打开
PITR production table 默认打开,恢复窗口 1-35 days
TTL 临时数据 / session / cache / event retention 可以打开
SSE 默认全量加密;敏感数据用 customer managed KMS key
Tags env, service, owner, cost-center, data-classification

capacity mode#

Mode When To Use 注意项
On-demand 新业务、流量不可预测、低运维成本优先 单表默认 quota 仍然存在;突发上量前要确认 Service Quotas
Provisioned 流量稳定、成本敏感、可预测峰值 需要 auto scaling / reserved capacity / 告警
on-demand:
    优点:
        不需要提前估算 RCU / WCU
        适合 spike / early stage workload

    注意:
        不是无限吞吐
        hot partition 仍然会 throttle
        大促 / migration 前要提前压测和检查 quota

provisioned:
    优点:
        成本更可控
        稳定大流量可以更便宜

    注意:
        auto scaling 有 CloudWatch 评估和 UpdateTable 延迟
        sudden spike 可能先 throttle 再扩容
        GSI 也要单独配置容量和 auto scaling

On-demand table 可以设置 Maximum read request units / Maximum write request units,这是 table 每秒吞吐上限,用来控制成本和防止异常流量打爆使用量。它不是 provisioned capacity,也不是预留容量,而是 cap / throttle limit。

Maximum read request units: 这张 on-demand table 每秒最多允许消耗多少 read request units
Maximum write request units: 这张 on-demand table 每秒最多允许消耗多少 write request units

example:
    Maximum read request units = 1000
    strong read 4 KB item: max about 1000 reads/s
    strong read 8 KB item: max about 500 reads/s
    eventual read 8 KB item: max about 1000 reads/s

    Maximum write request units = 1000
    write 900 B item: max about 1000 writes/s
    write 1.2 KB item: max about 500 writes/s

exceed limit:
    read exceeds maximum read request units: read requests are throttled
    write exceeds maximum write request units: write requests are throttled

注意:
    AWS SDK may retry throttled requests
    sustained throttling still increases latency or causes failures
    hot partition can throttle even when table total throughput is below this limit

Warm throughput 不是 enable / disable 开关,也不是 on-demand maximum throughput。它表示 table / secondary index 当前已经 warm 好、可以马上承接的 read/write 吞吐能力;如果预计大促、迁移、批量导入等峰值流量,可以提前调高 warm throughput。

Maximum read/write request units: on-demand table 的最高上限,超过会 throttle
Warm throughput: 当前可立即支撑的吞吐能力 / 可预热目标,不是 cap

capacity units#

Term Meaning How To Read
RCU Read Capacity Unit,读容量单位 1 秒内读取最多 4 KB item 的能力
WCU Write Capacity Unit,写容量单位 1 秒内写入最多 1 KB item 的能力
read request unit On-demand 读请求计费单位 计算方式和 RCU 类似,但不需要提前 provision
write request unit On-demand 写请求计费单位 计算方式和 WCU 类似,但不需要提前 provision
consumed capacity 实际消耗的容量 CloudWatch 里看 ConsumedReadCapacityUnits / ConsumedWriteCapacityUnits
provisioned capacity 配置的容量上限 CloudWatch 里看 ProvisionedReadCapacityUnits / ProvisionedWriteCapacityUnits

RCU 计算:

eventually consistent read: 0.5 RCU per 4 KB

strongly consistent read: 1 RCU per 4 KB

transactional read: 2 RCU per 4 KB

rounding: item size 按 4 KB 向上取整

examples:
    read 3 KB item, eventual consistency: 0.5 RCU
    read 8 KB item, eventual consistency: 1 RCU
    read 8 KB item, strong consistency: 2 RCU
    read 64 KB item, eventual consistency: 8 RCU
    read 64 KB item, strong consistency: 16 RCU

WCU 计算:

standard write: 1 WCU per 1 KB

transactional write: 2 WCU per 1 KB

rounding: item size 按 1 KB 向上取整

examples:
    write 900 B item: 1 WCU
    write 1.2 KB item: 2 WCU
    transactional write 1.2 KB item: 4 WCU

GSI / LSI 影响:

GSI:
    table write 会同时写入匹配的 GSI
    GSI projected attributes 越大,写入 GSI 的 WCU 越高
    读 GSI 消耗 GSI 自己的 read capacity
    provisioned mode 下,GSI 要单独配置 capacity / auto scaling

LSI:
    和 base table 共用 capacity
    只支持 strong / eventual read,不支持跨 partition query

quotas#

常见 quota:
    item max size: 400 KB
    LSI per table: 5
    GSI per table: default 20
    projected attributes across secondary indexes: 100
    tables per account per region: default 2500
    default table-level throughput quota:
        on-demand: 40000 read request units / 40000 write request units
        provisioned: 40000 RCU / 40000 WCU
    default account-level provisioned quota: 80000 RCU / 80000 WCU per region

hot partition limit:
    one partition max:
        3000 RCU / second
        1000 WCU / second

注意:
    quota 是 per region
    default quota 不是架构上限,可以申请提高
    hot partition 不能只靠提高 table quota 解决

3. Data Modeling Best Practices#

DynamoDB Primary Key

DynamoDB 的 primary key 决定两件事:
    1. item 的唯一性
    2. 最基础的查询方式

Primary key 有两种形式:

simple primary key:
    只设置 partition key
    partition key 一个字段决定唯一性

composite primary key:
    同时设置 partition key + sort key
    partition key + sort key 两个字段一起决定唯一性
Partition key

partition key 是 DynamoDB 用来决定 item 属于哪个分区 / 分组的 key。

可以简单理解为:
    partition key 决定大分组

例子:
    pk = USER#u1

含义:
    这个 item 属于 USER#u1 这个用户分组
Sort key

sort key 只在 composite primary key 里存在。

可以简单理解为:
    sort key 决定这个分组里的具体 item
    sort key 也支持排序 / 范围查询

例子:
    pk = USER#u1
    sk = ORDER#o1001

含义:
    USER#u1 这个用户分组下的一条订单
唯一性规则

simple primary key:
    pk 必须唯一

example:
    pk = USER#u1

表里不能同时有两条:
    pk = USER#u1
    pk = USER#u1

composite primary key:
    pk + sk 组合必须唯一

example:
    pk = USER#u1, sk = ORDER#o1001

表里可以有:
    pk = USER#u1, sk = PROFILE
    pk = USER#u1, sk = ORDER#o1001
    pk = USER#u1, sk = ORDER#o1002

但不能重复:
    pk = USER#u1, sk = ORDER#o1001
    pk = USER#u1, sk = ORDER#o1001
一句话总结

只设置 partition key:
    simple primary key
    一个字段决定唯一性

同时设置 partition key + sort key:
    composite primary key
    两个字段组合决定唯一性

partition key:
    决定大分组

sort key:
    决定分组里的具体 item
    支持排序 / 范围查询

4. Query / Write Best Practices#

Query vs Scan#

Query:
    必须指定 partition key
    可以用 sort key condition
    适合在线请求

Scan:
    会读很多 item
    filter expression 是读完后过滤,不会减少读取容量
    只适合 backfill / admin job / small table

production rule:
    API request path 不要做 full table scan
    如果必须 scan:
        limit page size
        use pagination
        run in background
        rate limit
        monitor consumed capacity and throttle

read consistency#

Read consistency 不是 table 创建时固定的配置,而是每次读请求选择。GetItem / Query / Scan 可以通过 ConsistentRead=true 请求 strong consistency;不设置时默认 eventual consistency。GSI 只支持 eventual consistency。

DynamoDB 是分布式存储。为了高可用、低延迟和扩展性,数据会放在多个副本 / 节点上。写入成功表示 DynamoDB 已经接受并持久化这次写入,但不同副本看到最新值可能有短暂的传播窗口。

eventual consistency:
    允许读请求命中一个短暂落后的副本
    优点是成本低、延迟低、吞吐 / 可用性更好
    缺点是刚写完立刻读,可能短暂看到旧值

strong consistency:
    读路径要保证返回最新成功写入后的值
    优点是 read-after-write 更可靠
    缺点是成本更高、限制更多,比如 GSI 不支持 strong read
eventually consistent read:
    default
    cost = 0.5 RCU per 4 KB
    suitable for most read path

strongly consistent read:
    cost = 1 RCU per 4 KB
    only table / LSI support
    GSI / streams do not support strong consistency

transactional read:
    cost = 2 RCU per 4 KB
    only use when real transaction semantics are needed

decision:
    default use eventual consistency
    read-after-write correctness required: use strong consistency on table / LSI
    reading from GSI: design for eventual consistency
    multi-item atomic correctness required: use transaction

DynamoDB replica example:
    initial value: PRODUCT#p1 stock = 10
    B writes stock = 9
    write success means DynamoDB has durably accepted the write, not that every read replica must already show it

    replica state may briefly be:
        replica-1: stock = 9
        replica-2: stock = 9
        replica-3: stock = 10

    eventual read:
        A may read replica-3 and briefly see stock = 10
        this does not mean B's write failed
        it means eventual read can read a briefly stale replica

    strong read:
        A reads base table with ConsistentRead=true
        DynamoDB must return stock = 9 after B's write succeeds

    transactional read:
        A reads multiple items such as PRODUCT#p1 and ORDER#o1001 in one transaction
        DynamoDB returns a transactionally consistent snapshot instead of a mixed view

write#

Write 没有像 read 那样的 eventual / strong consistency 开关,也不提供用户可配置的 write consistency level。DynamoDB 返回写入成功,就表示服务端已经按自己的复制和持久化协议接受这次写入;standard / transactional write 讲的是写入范围和原子性,不是几个副本确认才算成功。

standard write:
    PutItem / UpdateItem / DeleteItem 写单个 item
    适合普通单 item 写入

conditional write:
    单个 item 写入,但带条件,防止并发错误
    example: stock > 0 才能扣库存

transactional write:
    多个 item 一起写
    example: 扣库存 + 创建订单 + 写 payment record
    任意一步失败,整体失败

related eventual paths:
    GSI index read 是 eventual consistency
    Global Tables 跨 Region 复制是 eventual consistency
write capacity:
    1 WCU = one write per second for item up to 1 KB
    item size is rounded up
    each GSI projection adds write cost

best practices:
    use UpdateExpression instead of rewriting large item
    keep item small
    avoid frequently changing huge attributes
    do not store large blob in DynamoDB; store in S3 and keep pointer
    use ReturnConsumedCapacity during test to estimate cost

conditional write#

use condition expression for correctness:
    create only if not exists
    update only if version matched
    decrement stock only if quantity > 0
    avoid lost update
aws dynamodb update-item \
  --table-name prod-order-orders \
  --key '{"pk":{"S":"ORDER#1001"},"sk":{"S":"META"}}' \
  --update-expression "SET #status = :paid, version = version + :one" \
  --condition-expression "version = :expected AND #status = :pending" \
  --expression-attribute-names '{"#status":"status"}' \
  --expression-attribute-values '{
    ":paid":{"S":"PAID"},
    ":pending":{"S":"PENDING"},
    ":expected":{"N":"1"},
    ":one":{"N":"1"}
  }' \
  --return-values ALL_NEW

retries#

client should retry:
    ProvisionedThroughputExceededException
    ThrottlingException
    InternalServerError
    ServiceUnavailable
    TransactionConflictException

retry policy:
    exponential backoff
    jitter
    max attempts
    idempotency token for write path

do not retry blindly:
    ConditionalCheckFailedException
    ValidationException
    AccessDeniedException

5. Index Best Practices#

GSI vs LSI#

GSI = Global Secondary Index,LSI = Local Secondary Index。GSI / LSI 是创建 index 时选择的类型,不是 DynamoDB 根据 key 是否相同自动分类。GSI 可以使用和 table partition key 一样的 attribute,例如 table 是 pk = user_id, sk = created_at,GSI 可以是 GSI partition key = user_id, GSI sort key = status;这看起来像 LSI,但 GSI 不能完全替代 LSI。

对比 LSI GSI
Partition key 必须和 table partition key 相同 可以相同,也可以不同
Sort key 必须不同 可选,可不同
创建时间 只能建表时创建,之后不能加 可以建表后新增 / 删除
一致性读取 支持 strongly consistent read 只支持 eventually consistent read
容量 使用 table 的读写容量 有自己的容量,On-demand 下也独立计费 / 消耗
数据同步 和 base table 更紧密 异步复制到 GSI
大小限制 同一个 partition key 下 item collection 有 10GB 限制 没有这个 LSI item collection 限制
LSI 有价值的场景:
    同一个 table partition key
    只是换一个 sort key 排序 / 范围查询
    需要 strongly consistent read
    建表时就确定索引

GSI 更适合:
    后续可以新增索引
    换不同 partition key 查询
    不需要强一致读
    更灵活地扩展查询模式

简单判断:
    同一个 pk + 需要强一致读 + 建表时就确定索引 -> LSI
    其他大多数情况 -> GSI

GSI#

GSI 用于新的 access pattern:
    base table key 无法支持时才加
    GSI key 也必须防 hot partition
    GSI read is eventually consistent
    GSI 有自己的 throttling / capacity / metrics

projection:
    KEYS_ONLY:
        cheapest
        only need keys

    INCLUDE:
        selected attributes
        good default for query result list

    ALL:
        convenient but expensive
        write amplification and storage cost high

注意:
    base table write 会同步写 GSI
    GSI backfill 可能消耗大量写容量
    GSI throttle can throttle base table write

LSI#

LSI:
    must be created with table
    same partition key as base table
    different sort key
    supports strong consistent read
    max 5 per table

practical rule:
    不确定就不要先加 LSI
    后续可变 access pattern 通常用 GSI

sparse index#

sparse index:
    only items with GSI key attributes appear in index
    useful for status / workflow / pending items

example:
    unpaid orders only have:
        gsi2pk = TENANT#<tenant_id>#STATUS#UNPAID
        gsi2sk = CREATED#<created_at>#ORDER#<order_id>

    paid orders remove gsi2pk / gsi2sk

6. Security Best Practices#

IAM#

principle:
    use IAM role, not long-term access key
    least privilege
    separate read role / write role / migration role / admin role
    allow table ARN and index ARN explicitly
    avoid dynamodb:* in application role
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowAppReadWriteOrders",
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:UpdateItem",
        "dynamodb:DeleteItem",
        "dynamodb:Query",
        "dynamodb:BatchGetItem",
        "dynamodb:BatchWriteItem"
      ],
      "Resource": [
        "arn:aws:dynamodb:ap-east-1:123456789012:table/prod-order-orders",
        "arn:aws:dynamodb:ap-east-1:123456789012:table/prod-order-orders/index/*"
      ]
    }
  ]
}

resource-based policy#

use cases:
    cross-account access
    restrict source VPC endpoint
    central data account

注意:
    explicit deny 优先级最高
    policy size has limit
    cross-account 要同时检查 principal policy and resource policy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyAccessUnlessFromVpce",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "dynamodb:*",
      "Resource": [
        "arn:aws:dynamodb:ap-east-1:123456789012:table/prod-order-orders",
        "arn:aws:dynamodb:ap-east-1:123456789012:table/prod-order-orders/index/*"
      ],
      "Condition": {
        "StringNotEquals": {
          "aws:SourceVpce": "vpce-0123456789abcdef0"
        }
      }
    }
  ]
}

VPC endpoint#

recommendation:
    EC2 / ECS / Lambda in VPC -> use DynamoDB VPC endpoint
    add endpoint policy
    add IAM/resource policy condition with aws:SourceVpce when appropriate

gateway endpoint:
    common for DynamoDB access from VPC
    no NAT gateway needed for DynamoDB traffic

interface endpoint / PrivateLink:
    use when architecture requires interface endpoint behavior
    client may need endpoint URL configuration

encryption#

at rest:
    DynamoDB encrypts all data at rest
    default uses AWS owned key
    sensitive / compliance workload use customer managed KMS key

in transit: use HTTPS/TLS

application side:
    对特别敏感字段可以 client-side encryption
    但加密字段通常不能直接作为 query key

data protection#

production defaults:
    PITR enabled
    deletion protection enabled
    CloudTrail enabled
    AWS Config / Security Hub rule reviewed
    backup restore runbook tested

PITR notes:
    recovery window: 1-35 days
    restore creates a new table
    LatestRestorableDateTime usually lags current time by about 5 minutes

7. TTL / Streams / Global Tables#

TTL#

TTL:
    attribute must be Number
    value is Unix epoch time in seconds
    expired item is deleted asynchronously
    expired item can still appear before background deletion
    filter expired items in read path if correctness requires it

good use cases:
    session
    idempotency record
    temporary token
    cache item
    short-lived event

not good:
    precise scheduled deletion
    compliance deletion with strict second-level SLA

streams#

DynamoDB Streams:
    near real-time change capture
    common integration with Lambda
    use for projection / async workflow / audit / cache invalidation

stream view types:
    KEYS_ONLY
    NEW_IMAGE
    OLD_IMAGE
    NEW_AND_OLD_IMAGES

注意:
    Lambda consumer must handle duplicate/retry
    downstream processing should be idempotent

global tables#

global tables:
    multi-region active-active
    replication is eventually consistent
    conflict reconciliation is last writer wins

use when:
    low latency read/write in multiple regions
    regional resilience is required

注意:
    not a replacement for relational global transaction
    conflict model must be acceptable
    monitor replication latency and pending replication
    TTL replicated deletes may incur replicated write cost in replica regions

8. Monitoring#

important metrics#

Some DynamoDB metrics are sparse / event-driven. For example, throttle and error metrics may not appear in CloudWatch / YACE until the corresponding event happens. Detailed datapoint conditions are covered in DynamoDB YACE Dashboard.

Area Metrics What To Watch
Capacity ConsumedReadCapacityUnits, ConsumedWriteCapacityUnits consumed vs provisioned / quota
Throttle ThrottledRequests, ReadThrottleEvents, WriteThrottleEvents any non-zero spike on production
Hot partition ReadKeyRangeThroughputThrottleEvents, WriteKeyRangeThroughputThrottleEvents key range / partition bottleneck
Provisioned throttle ReadProvisionedThroughputThrottleEvents, WriteProvisionedThroughputThrottleEvents provisioned capacity insufficient
Account limit ReadAccountLimitThrottleEvents, WriteAccountLimitThrottleEvents account-level quota hit
On-demand max ReadMaxOnDemandThroughputThrottleEvents, WriteMaxOnDemandThroughputThrottleEvents on-demand table max hit
Latency SuccessfulRequestLatency p90 / p95 / p99 by operation
Errors SystemErrors, UserErrors AWS side vs client side errors
Conditional ConditionalCheckFailedRequests optimistic locking / business conflict
Transaction TransactionConflict high contention transaction
Result size ReturnedItemCount, ReturnedBytes query efficiency
TTL TimeToLiveDeletedItemCount TTL deletion activity
GSI backfill OnlineIndexPercentageProgress, OnlineIndexThrottleEvents, OnlineIndexConsumedWriteCapacity adding GSI impact
Global table ReplicationLatency, PendingReplicationCount, AgeOfOldestUnreplicatedRecord replica lag

alert rules#

critical:
    SystemErrors > 0 for 5m
    ReadThrottleEvents / WriteThrottleEvents > 0 for 5m on critical table
    ReadAccountLimitThrottleEvents / WriteAccountLimitThrottleEvents > 0
    ReplicationLatency above RPO expectation

warning:
    ConsumedReadCapacityUnits > 80% provisioned for 10m
    ConsumedWriteCapacityUnits > 80% provisioned for 10m
    SuccessfulRequestLatency p95 above service SLO
    ConditionalCheckFailedRequests sudden spike
    ReturnedItemCount too high for online query

dashboard#

dashboard should include:
    request latency p50 / p95 / p99 by operation
    read/write consumed capacity
    read/write throttle events
    key range throttle events
    system errors / user errors
    top application errors from logs
    GSI capacity and throttles
    table size / item count
    TTL deletes
    global table replication latency, if used

Prometheus / YACE#

apiVersion: v1alpha1
discovery:
  jobs:
    - type: AWS/DynamoDB
      regions:
        - ap-east-1
      customTags:
        - key: environment
          value: uat
      metrics:
        - name: ConsumedReadCapacityUnits
          statistics: [Sum]
          period: 60
          length: 300
        - name: ConsumedWriteCapacityUnits
          statistics: [Sum]
          period: 60
          length: 300
        - name: ReadThrottleEvents
          statistics: [Sum]
          period: 60
          length: 300
        - name: WriteThrottleEvents
          statistics: [Sum]
          period: 60
          length: 300
        - name: SuccessfulRequestLatency
          statistics: [Average, p95]
          period: 60
          length: 300
        - name: SystemErrors
          statistics: [Sum]
          period: 60
          length: 300
      dimensionNameRequirements:
        - TableName

9. Hands-on#

create table#

export AWS_PAGER=""
export AWS_REGION="ap-east-1"
export TABLE_NAME="dev-order-orders"

aws dynamodb create-table \
  --region "${AWS_REGION}" \
  --table-name "${TABLE_NAME}" \
  --billing-mode PAY_PER_REQUEST \
  --attribute-definitions \
    AttributeName=pk,AttributeType=S \
    AttributeName=sk,AttributeType=S \
    AttributeName=gsi1pk,AttributeType=S \
    AttributeName=gsi1sk,AttributeType=S \
  --key-schema \
    AttributeName=pk,KeyType=HASH \
    AttributeName=sk,KeyType=RANGE \
  --global-secondary-indexes '[
    {
      "IndexName": "gsi1",
      "KeySchema": [
        {"AttributeName": "gsi1pk", "KeyType": "HASH"},
        {"AttributeName": "gsi1sk", "KeyType": "RANGE"}
      ],
      "Projection": {"ProjectionType": "INCLUDE", "NonKeyAttributes": ["status", "amount", "created_at"]}
    }
  ]' \
  --deletion-protection-enabled \
  --tags \
    Key=env,Value=dev \
    Key=service,Value=order \
    Key=owner,Value=platform

enable PITR#

aws dynamodb update-continuous-backups \
  --region "${AWS_REGION}" \
  --table-name "${TABLE_NAME}" \
  --point-in-time-recovery-specification PointInTimeRecoveryEnabled=true,RecoveryPeriodInDays=35
aws dynamodb describe-continuous-backups \
  --region "${AWS_REGION}" \
  --table-name "${TABLE_NAME}" \
  --query 'ContinuousBackupsDescription.PointInTimeRecoveryDescription'

enable TTL#

aws dynamodb update-time-to-live \
  --region "${AWS_REGION}" \
  --table-name "${TABLE_NAME}" \
  --time-to-live-specification Enabled=true,AttributeName=expire_at

put items#

aws dynamodb put-item \
  --region "${AWS_REGION}" \
  --table-name "${TABLE_NAME}" \
  --condition-expression "attribute_not_exists(pk) AND attribute_not_exists(sk)" \
  --item '{
    "pk": {"S": "USER#u-1001"},
    "sk": {"S": "ORDER#2026-05-29T10:00:00Z#o-1001"},
    "gsi1pk": {"S": "ORDER#o-1001"},
    "gsi1sk": {"S": "META"},
    "order_id": {"S": "o-1001"},
    "user_id": {"S": "u-1001"},
    "status": {"S": "PENDING"},
    "amount": {"N": "99.90"},
    "version": {"N": "1"},
    "created_at": {"S": "2026-05-29T10:00:00Z"},
    "expire_at": {"N": "1790599200"}
  }'

query by user#

aws dynamodb query \
  --region "${AWS_REGION}" \
  --table-name "${TABLE_NAME}" \
  --key-condition-expression "pk = :pk AND begins_with(sk, :prefix)" \
  --expression-attribute-values '{
    ":pk": {"S": "USER#u-1001"},
    ":prefix": {"S": "ORDER#"}
  }' \
  --return-consumed-capacity TOTAL

query by order id through GSI#

aws dynamodb query \
  --region "${AWS_REGION}" \
  --table-name "${TABLE_NAME}" \
  --index-name gsi1 \
  --key-condition-expression "gsi1pk = :pk AND gsi1sk = :sk" \
  --expression-attribute-values '{
    ":pk": {"S": "ORDER#o-1001"},
    ":sk": {"S": "META"}
  }' \
  --return-consumed-capacity TOTAL

cloudwatch alarms#

aws cloudwatch put-metric-alarm \
  --region "${AWS_REGION}" \
  --alarm-name "dynamodb-${TABLE_NAME}-write-throttle" \
  --namespace AWS/DynamoDB \
  --metric-name WriteThrottleEvents \
  --statistic Sum \
  --period 60 \
  --evaluation-periods 5 \
  --threshold 0 \
  --comparison-operator GreaterThanThreshold \
  --treat-missing-data notBreaching \
  --dimensions Name=TableName,Value="${TABLE_NAME}"
aws cloudwatch put-metric-alarm \
  --region "${AWS_REGION}" \
  --alarm-name "dynamodb-${TABLE_NAME}-system-errors" \
  --namespace AWS/DynamoDB \
  --metric-name SystemErrors \
  --statistic Sum \
  --period 60 \
  --evaluation-periods 5 \
  --threshold 0 \
  --comparison-operator GreaterThanThreshold \
  --treat-missing-data notBreaching \
  --dimensions Name=TableName,Value="${TABLE_NAME}"
aws cloudwatch put-metric-alarm \
  --region "${AWS_REGION}" \
  --alarm-name "dynamodb-${TABLE_NAME}-p95-latency" \
  --namespace AWS/DynamoDB \
  --metric-name SuccessfulRequestLatency \
  --extended-statistic p95 \
  --period 60 \
  --evaluation-periods 5 \
  --threshold 50 \
  --comparison-operator GreaterThanThreshold \
  --treat-missing-data notBreaching \
  --dimensions Name=TableName,Value="${TABLE_NAME}" Name=Operation,Value=Query

cleanup#

# production table 不要直接执行 cleanup
aws dynamodb update-table \
  --region "${AWS_REGION}" \
  --table-name "${TABLE_NAME}" \
  --no-deletion-protection-enabled

aws dynamodb delete-table \
  --region "${AWS_REGION}" \
  --table-name "${TABLE_NAME}"

10. Production Checklist#

before launch:
    access patterns reviewed
    partition key distribution tested
    item size measured
    ReturnConsumedCapacity sampled in load test
    on-demand/provisioned mode decided
    Service Quotas checked
    PITR enabled
    deletion protection enabled
    IAM least privilege reviewed
    KMS key policy reviewed, if using customer managed key
    VPC endpoint / resource policy reviewed
    CloudWatch alarms created
    dashboard created
    backup restore tested
    migration / backfill has rate limit

when incident happens:
    check throttle reason first
    check table and GSI metrics separately
    check key range throttle events for hot partition
    check account limit throttle events for quota issue
    check app retry and timeout
    check recent GSI creation / backfill / migration