DynamoDB Modeling, RDS Scaling and Data Resilience

Design DynamoDB tables around access patterns, then scale and protect relational databases with replicas, proxies and Multi-AZ.

Intermediate⏱ 5 min readLesson 19 of 26#aws#dynamodb#rds#aurora#rds-proxy#read-replica#multi-az#gsi

DynamoDB: design for questions, not entities

In SQL you model data first and query later. In DynamoDB you list your access patterns first, then design keys to serve them.

Example access patterns for a shop:

  1. Get a customer by ID.
  2. List a customer's orders, newest first.
  3. Get one order with its items.
  4. Find orders by status.

Keys

KeyRole
Partition key (PK)Hashed to choose the storage partition; must spread load evenly
Sort key (SK)Orders items inside a partition; enables range queries

Single-table design stores related items together:

PKSKData
CUSTOMER#42PROFILEname, email
CUSTOMER#42ORDER#2025-03-01#9001total, status
CUSTOMER#42ORDER#2025-03-07#9014total, status
# All orders for customer 42, newest first
aws dynamodb query --table-name shop \
  --key-condition-expression "PK = :pk AND begins_with(SK, :o)" \
  --expression-attribute-values '{":pk":{"S":"CUSTOMER#42"},":o":{"S":"ORDER#"}}' \
  --no-scan-index-forward

Indexes

  • GSI (global secondary index): a different PK/SK, eventually consistent, its own throughput. Use for "orders by status".
  • LSI: same PK, different SK; must be created with the table.
  • Use sparse indexes: only items that have the index attribute appear in it.

Pitfalls

  • Hot partitions from a low-cardinality key (such as status=ACTIVE). Add a suffix or shard the key.
  • Scan reads the entire table. Avoid it in application paths.
  • Items are limited to 400 KB; store large blobs in S3 and keep the pointer.
  • Choose on-demand capacity for unpredictable traffic and provisioned with auto scaling for steady traffic.

Useful features

FeatureUse
TTLBackground expiry cleanup; not an immediate authorization check
StreamsTrigger Lambda on changes; build projections
TransactionsAll-or-nothing across up to 100 items
Conditional writesOptimistic locking: attribute_not_exists(PK)
DAXIn-memory cache for microsecond reads
Global tablesMulti-region replication with a selected consistency mode
PITRPoint-in-time recovery for the last 35 days

Relational scaling on RDS and Aurora

Drawing diagram…

Multi-AZ is for availability

  • RDS Multi-AZ keeps a synchronous standby in another AZ and fails over automatically (typically 1 to 2 minutes). The standby does not serve reads in the classic single-standby setup.
  • Aurora stores data in six copies across three AZs, and failover to a replica is usually faster.

Read replicas are for read scale

  • Asynchronous, so reads can be slightly stale (replica lag).
  • Route reporting and read-heavy queries there. Do not read-your-own-write from a replica without handling lag.
  • Aurora offers a reader endpoint that balances over replicas.

RDS Proxy for connection storms

Lambda and autoscaling containers can open thousands of connections and exhaust the database. RDS Proxy pools and reuses connections, and speeds up failover because apps stay connected to the proxy.

Other scaling tools

  • Aurora Serverless v2 scales capacity in fine steps for variable load.
  • Aurora Global Database replicates to other regions with typically under a second of lag, for low-latency reads and disaster recovery.
  • ElastiCache (Redis or Valkey) absorbs repeated reads.
  • Fix queries first: use CloudWatch Database Insights, add indexes, and check slow-query logs before buying a bigger instance.

Backups and recovery

MechanismNotes
Automated backups + PITRRestore to any second within retention (up to 35 days) into a new instance
Manual snapshotsKept until deleted; can be copied across regions and accounts
AWS BackupCentral policies, cross-account and cross-region copies, vault lock

Restores create a new database, so plan the endpoint switch. Test restores regularly.

Choosing quickly

NeedPick
Known access patterns, huge scale, low opsDynamoDB
Joins, ad-hoc queries, transactionsAurora or RDS
Variable relational loadAurora Serverless v2
Sub-millisecond repeated readsElastiCache or DAX

Worked conditional update: reserve the last book

A stock item has key BOOK#42 and an integer stock. Two customers race for the final copy. A separate read followed by an unconditional update is unsafe: both can observe one remaining item.

In a dedicated sample table with that key schema, an atomic conditional update can decrement only when stock remains:

aws dynamodb update-item --table-name academy-stock \
  --key '{"PK":{"S":"BOOK#42"}}' \
  --update-expression 'SET stock = stock - :one' \
  --condition-expression 'stock >= :one' \
  --expression-attribute-values '{":one":{"N":"1"}}' \
  --return-values ALL_NEW --profile academy

This assumes an existing numeric stock field. A failed condition is an expected business outcome; it is not a reason to retry unconditionally. If you must reserve stock and create an order together, design an appropriate transaction. A stock decrement alone is not idempotent if a caller retries after losing the response.

Pagination and index freshness

A query can return a page plus a continuation key. Continue using that key when the client needs more results; do not assume one request returns all records. Apply authorization to every page and bound requested result sizes.

GSIs are eventually consistent. Immediately querying an index after writing an order may not show it yet. For read-after-write behavior, use a suitable primary-key read or an explicit pending state rather than treating a missing index result as a failed write. See read consistency.

RDS scaling exercise

Calculate your connection budget across app replicas and workers. A proxy can help with pooling, but it does not make an inefficient query fast or automatically distribute writes and reads. Ordinary RDS instance proxies target the writer, not a separately replicated read replica; supported cluster configurations can provide dedicated read-only proxy endpoints. Check RDS Proxy endpoints.

Deliverable: document one immediate-consistency operation, one lag-tolerant reporting operation, and the endpoint each uses. Restore a sample backup to a new database, verify records and permissions, then remove the dedicated recovery resources.

Remember this

  • DynamoDB: write down access patterns first, avoid scans and hot keys.
  • Multi-AZ gives availability; read replicas give read scale.
  • Use RDS Proxy with Lambda and bursty clients.
  • Backups matter only if restores are tested.