Skip to content

Dynamodb

Chapter 23: Amazon DynamoDB - NoSQL Database

Section titled “Chapter 23: Amazon DynamoDB - NoSQL Database”

Amazon DynamoDB is a fully managed, serverless, key-value NoSQL database designed for single-digit millisecond performance at any scale.

DynamoDB Overview
+------------------------------------------------------------------+
| |
| +------------------------+ |
| | DynamoDB | |
| +------------------------+ |
| | |
| +---------------------+---------------------+ |
| | | | |
| v v v |
| +----------+ +----------+ +----------+ |
| | Serverless| | Scalable | | Fast | |
| | | | | | | |
| | - No | | - Auto | | - <10ms | |
| | servers| | scaling| | latency| |
| | - Managed| | - Any | | - Multi-AZ| |
| | | | scale | | | |
| +----------+ +----------+ +----------+ |
| |
| Key Features: |
| - Fully managed, serverless |
| - Single-digit millisecond latency |
| - Automatic scaling |
| - Multi-AZ replication |
| - Global tables (multi-region) |
| |
+------------------------------------------------------------------+

DynamoDB Data Model
+------------------------------------------------------------------+
| |
| Table Structure |
| +----------------------------------------------------------+ |
| | | |
| | Table: Users | |
| | +----------------------------------------------------+ | |
| | | Primary Key | Attributes | | |
| | |--------------|--------------------------------------| | |
| | | PK | SK | Name | Email | Status | | |
| | |-------|------|---------|--------------|-----------| | |
| | | USER1 | null | John | john@ex.com | active | | |
| | | USER2 | null | Jane | jane@ex.com | active | | |
| | | USER3 | null | Bob | bob@ex.com | inactive | | |
| | +----------------------------------------------------+ | |
| | | |
| +----------------------------------------------------------+ |
| |
| Primary Key Types: |
| +----------------------------------------------------------+ |
| | | |
| | 1. Simple Primary Key (Partition Key only) | |
| | - Single attribute identifies item | |
| | - Example: UserId | |
| | | |
| | 2. Composite Primary Key (Partition + Sort Key) | |
| | - Two attributes identify item | |
| | - Partition Key: Hash | |
| | - Sort Key: Range | |
| | - Example: UserId + Timestamp | |
| | | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
DynamoDB Items and Attributes
+------------------------------------------------------------------+
| |
| Item (Row equivalent) |
| +----------------------------------------------------------+ |
| | | |
| | { | |
| | "UserId": "USER1", // Partition Key | |
| | "Timestamp": 1234567890, // Sort Key | |
| | "Name": "John Doe", | |
| | "Email": "john@example.com", | |
| | "Age": 30, | |
| | "IsActive": true, | |
| | "Tags": ["premium", "verified"], | |
| | "Address": { | |
| | "Street": "123 Main St", | |
| | "City": "New York", | |
| | "Zip": "10001" | |
| | } | |
| | } | |
| | | |
| +----------------------------------------------------------+ |
| |
| Attribute Types: |
| +----------------------------------------------------------+ |
| | Scalar Types: | |
| | - S (String) | |
| | - N (Number) | |
| | - B (Binary) | |
| | - BOOL (Boolean) | |
| | - NULL (Null) | |
| | | |
| | Document Types: | |
| | - M (Map) - JSON object | |
| | - L (List) - Array | |
| | | |
| | Set Types: | |
| | - SS (String Set) | |
| | - NS (Number Set) | |
| | - BS (Binary Set) | |
| | | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

DynamoDB On-Demand Mode
+------------------------------------------------------------------+
| |
| Features: |
| +----------------------------------------------------------+ |
| | | |
| | - Pay per request | |
| | - No capacity planning | |
| | - Instant scaling | |
| | - No throttling (within service limits) | |
| | | |
| | Pricing: | |
| | - Read: $1.25 per million request units | |
| | - Write: $1.25 per million write units | |
| | - Storage: $0.25 per GB-month | |
| | | |
| | Use Cases: | |
| | - Unpredictable traffic | |
| | - New applications | |
| | - Development/testing | |
| | | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
DynamoDB Provisioned Mode
+------------------------------------------------------------------+
| |
| Read Capacity Units (RCU) |
| +----------------------------------------------------------+ |
| | | |
| | 1 RCU = 1 strongly consistent read per second | |
| | for items up to 4 KB | |
| | | |
| | 0.5 RCU = 1 eventually consistent read per second | |
| | | |
| | Example: | |
| | - Item size: 8 KB | |
| | - Strongly consistent: 2 RCU | |
| | - Eventually consistent: 1 RCU | |
| | | |
| +----------------------------------------------------------+ |
| |
| Write Capacity Units (WCU) |
| +----------------------------------------------------------+ |
| | | |
| | 1 WCU = 1 write per second | |
| | for items up to 1 KB | |
| | | |
| | Example: | |
| | - Item size: 5 KB | |
| | - Required: 5 WCU | |
| | | |
| +----------------------------------------------------------+ |
| |
| Auto Scaling |
| +----------------------------------------------------------+ |
| | | |
| | Configuration: | |
| | - Minimum capacity | |
| | - Maximum capacity | |
| | - Target utilization (e.g., 70%) | |
| | | |
| | Scaling: | |
| | - Automatic increase/decrease | |
| | - Based on CloudWatch metrics | |
| | | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

Global Secondary Indexes
+------------------------------------------------------------------+
| |
| Purpose: Query on non-key attributes |
| |
| Architecture: |
| +----------------------------------------------------------+ |
| | | |
| | Table: Users | |
| | +----------------------------------------------------+ | |
| | | PK: UserId | SK: null | Email | Status | | |
| | |-------------|---------|--------------|-----------| | |
| | | USER1 | - | john@ex.com | active | | |
| | | USER2 | - | jane@ex.com | active | | |
| | +----------------------------------------------------+ | |
| | | | |
| | v | |
| | GSI: EmailIndex | |
| | +----------------------------------------------------+ | |
| | | PK: Email | SK: Status | UserId | | | |
| | |----------------|-------------|-----------|--------| | |
| | | john@ex.com | active | USER1 | | | |
| | | jane@ex.com | active | USER2 | | | |
| | +----------------------------------------------------+ | |
| | | |
| +----------------------------------------------------------+ |
| |
| Features: |
| - Different partition key than table |
| - Can have sort key |
| - Projected attributes (all, keys-only, include) |
| - Consumes separate RCU/WCU |
| - Up to 20 GSIs per table |
| |
+------------------------------------------------------------------+
Local Secondary Indexes
+------------------------------------------------------------------+
| |
| Purpose: Alternative sort key for same partition key |
| |
| Architecture: |
| +----------------------------------------------------------+ |
| | | |
| | Table: Orders | |
| | +----------------------------------------------------+ | |
| | | PK: UserId | SK: OrderDate | Amount | Status | | |
| | |-------------|-------------|--------|-----------| | |
| | | USER1 | 2024-01-01 | 100 | shipped | | |
| | | USER1 | 2024-01-15 | 200 | pending | | |
| | | USER2 | 2024-01-02 | 150 | shipped | | |
| | +----------------------------------------------------+ | |
| | | | |
| | v | |
| | LSI: AmountIndex | |
| | +----------------------------------------------------+ | |
| | | PK: UserId | SK: Amount | OrderDate | Status | | |
| | |-------------|-------------|-----------|---------| | |
| | | USER1 | 100 | 2024-01-01| shipped | | |
| | | USER1 | 200 | 2024-01-15| pending | | |
| | | USER2 | 150 | 2024-01-02| shipped | | |
| | +----------------------------------------------------+ | |
| | | |
| +----------------------------------------------------------+ |
| |
| Features: |
| - Same partition key as table |
| - Different sort key |
| - Must be created at table creation |
| - Up to 5 LSIs per table |
| - Shares RCU/WCU with table |
| |
+------------------------------------------------------------------+
DynamoDB Streams
+------------------------------------------------------------------+
| |
| Purpose: Capture table modifications |
| |
| Architecture: |
| +----------------------------------------------------------+ |
| | | |
| | DynamoDB Table | |
| | +------------------+ | |
| | | Item Operations | | |
| | | - INSERT | | |
| | | - MODIFY | | |
| | | - REMOVE | | |
| | +------------------+ | |
| | | | |
| | v | |
| | DynamoDB Stream | |
| | +------------------+ | |
| | | Stream Records | | |
| | | (24-hour retention) | |
| | +------------------+ | |
| | | | |
| | +----+----+ | |
| | | | | |
| | v v | |
| | +------+ +----------+ | |
| | |Lambda| | Kinesis | | |
| | | | | KCL App | | |
| | +------+ +----------+ | |
| | | |
| +----------------------------------------------------------+ |
| |
| Stream View Types: |
| +----------------------------------------------------------+ |
| | - KEYS_ONLY: Only key attributes | |
| | - NEW_IMAGE: Entire new item | |
| | - OLD_IMAGE: Entire old item | |
| | - NEW_AND_OLD_IMAGES: Both versions | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
DynamoDB Global Tables
+------------------------------------------------------------------+
| |
| Purpose: Multi-region, multi-active replication |
| |
| Architecture: |
| +----------------------------------------------------------+ |
| | | |
| | US-East-1 EU-West-1 AP-South-1 | |
| | +----------+ +----------+ +----------+ | |
| | | Table | | Table | | Table | | |
| | | Replica |<-------->| Replica |<------>| Replica | | |
| | +----------+ +----------+ +----------+ | |
| | ^ ^ ^ | |
| | | | | | |
| | Application Application Application | |
| | (Read/Write) (Read/Write) (Read/Write)| |
| | | |
| +----------------------------------------------------------+ |
| |
| Features: |
| - Multi-active replication |
| - Last-writer-wins conflict resolution |
| - < 1 second replication |
| - Requires DynamoDB Streams |
| - Same table name in all regions |
| |
+------------------------------------------------------------------+

DynamoDB DAX
+------------------------------------------------------------------+
| |
| Purpose: In-memory caching for DynamoDB |
| |
| Architecture: |
| +----------------------------------------------------------+ |
| | | |
| | Application | |
| | +------------------+ | |
| | | | | |
| | +------------------+ | |
| | | | |
| | v | |
| | DAX Cluster | |
| | +------------------+ | |
| | | Primary Node | | |
| | | +------------+ | | |
| | | | Cache | | | |
| | | +------------+ | | |
| | | | Replica 1 | | | |
| | | | Replica 2 | | | |
| | +------------------+ | |
| | | | |
| | v | |
| | DynamoDB Table | |
| | +------------------+ | |
| | | | | |
| | +------------------+ | |
| | | |
| +----------------------------------------------------------+ |
| |
| Features: |
| - Microsecond latency |
| - Write-through caching |
| - Eventually consistent reads |
| - Automatic failover |
| - Compatible with DynamoDB API |
| |
| Performance: |
| - 10x improvement over DynamoDB |
| - Up to millions of requests per second |
| |
+------------------------------------------------------------------+

# ============================================================
# DynamoDB Table
# ============================================================
resource "aws_dynamodb_table" "users" {
name = "users"
billing_mode = "PAY_PER_REQUEST" # On-demand
# Primary Key
hash_key = "UserId"
range_key = "CreatedAt"
# Attributes
attribute {
name = "UserId"
type = "S"
}
attribute {
name = "CreatedAt"
type = "N"
}
# Global Secondary Index
attribute {
name = "Email"
type = "S"
}
global_secondary_index {
name = "EmailIndex"
hash_key = "Email"
range_key = "CreatedAt"
projection_type = "ALL"
}
# Stream
stream_enabled = true
stream_view_type = "NEW_AND_OLD_IMAGES"
# TTL
ttl {
attribute_name = "ExpiresAt"
enabled = true
}
# Point-in-time Recovery
point_in_time_recovery {
enabled = true
}
# Server-side encryption
server_side_encryption {
enabled = true
kms_key_arn = aws_kms_key.dynamodb.arn
}
# Table class
table_class = "STANDARD" # or "STANDARD_INFREQUENT_ACCESS"
tags = {
Name = "users-table"
}
}
# ============================================================
# DynamoDB Table with Provisioned Capacity
# ============================================================
resource "aws_dynamodb_table" "orders" {
name = "orders"
billing_mode = "PROVISIONED"
read_capacity = 20
write_capacity = 10
hash_key = "OrderId"
range_key = "OrderDate"
attribute {
name = "OrderId"
type = "S"
}
attribute {
name = "OrderDate"
type = "S"
}
# Local Secondary Index
attribute {
name = "Amount"
type = "N"
}
local_secondary_index {
name = "AmountIndex"
range_key = "Amount"
projection_type = "ALL"
}
tags = {
Name = "orders-table"
}
}
# ============================================================
# Auto Scaling for Provisioned Table
# ============================================================
# Read capacity auto scaling
resource "aws_appautoscaling_target" "read" {
max_capacity = 100
min_capacity = 5
resource_id = "table/${aws_dynamodb_table.orders.name}"
scalable_dimension = "dynamodb:table:ReadCapacityUnits"
service_namespace = "dynamodb"
}
resource "aws_appautoscaling_policy" "read" {
name = "read-scaling-policy"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.read.resource_id
scalable_dimension = aws_appautoscaling_target.read.scalable_dimension
service_namespace = aws_appautoscaling_target.read.service_namespace
target_tracking_scaling_policy_configuration {
target_value = 70
predefined_metric_specification {
predefined_metric_type = "DynamoDBReadCapacityUtilization"
}
}
}
# Write capacity auto scaling
resource "aws_appautoscaling_target" "write" {
max_capacity = 100
min_capacity = 5
resource_id = "table/${aws_dynamodb_table.orders.name}"
scalable_dimension = "dynamodb:table:WriteCapacityUnits"
service_namespace = "dynamodb"
}
resource "aws_appautoscaling_policy" "write" {
name = "write-scaling-policy"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.write.resource_id
scalable_dimension = aws_appautoscaling_target.write.scalable_dimension
service_namespace = aws_appautoscaling_target.write.service_namespace
target_tracking_scaling_policy_configuration {
target_value = 70
predefined_metric_specification {
predefined_metric_type = "DynamoDBWriteCapacityUtilization"
}
}
}
# ============================================================
# Global Table
# ============================================================
# Primary region table
resource "aws_dynamodb_table" "global" {
provider = aws.primary
name = "global-table"
billing_mode = "PAY_PER_REQUEST"
hash_key = "Id"
attribute {
name = "Id"
type = "S"
}
stream_enabled = true
stream_view_type = "NEW_AND_OLD_IMAGES"
# Enable global table
replica {
region_name = "us-east-1"
}
replica {
region_name = "eu-west-1"
}
}
# ============================================================
# DAX Cluster
# ============================================================
resource "aws_dax_cluster" "main" {
cluster_name = "main-dax"
node_type = "dax.t3.small"
replication_factor = 3
# IAM role
iam_role_arn = aws_iam_role.dax.arn
# VPC configuration
subnet_group_name = aws_dax_subnet_group.main.name
security_group_ids = [aws_security_group.dax.id]
# Parameter group
parameter_group_name = "default.dax-1.0"
tags = {
Name = "main-dax"
}
}
resource "aws_dax_subnet_group" "main" {
name = "main-dax-subnet"
subnet_ids = var.private_subnet_ids
}
# ============================================================
# DynamoDB Stream to Lambda
# ============================================================
resource "aws_lambda_function" "process_stream" {
function_name = "process-dynamodb-stream"
role = aws_iam_role.lambda.arn
runtime = "python3.11"
handler = "index.handler"
filename = "function.zip"
source_code_hash = filebase64sha256("function.zip")
}
resource "aws_lambda_event_source_mapping" "stream" {
event_source_arn = aws_dynamodb_table.users.stream_arn
function_name = aws_lambda_function.process_stream.arn
starting_position = "LATEST"
# Batch size
batch_size = 100
# Filter criteria (optional)
filter_criteria {
filter {
pattern = jsonencode({
dynamodb = {
Keys = {
UserId = {
S = ["USER1"]
}
}
}
})
}
}
}

DynamoDB Operations
+------------------------------------------------------------------+
| |
| Item Operations |
| +----------------------------------------------------------+ |
| | | |
| | PutItem: Create or replace item | |
| | GetItem: Retrieve item by key | |
| | UpdateItem: Update item attributes | |
| | DeleteItem: Delete item by key | |
| | BatchGetItem: Get multiple items | |
| | BatchWriteItem: Put/delete multiple items | |
| | | |
| +----------------------------------------------------------+ |
| |
| Query Operations |
| +----------------------------------------------------------+ |
| | | |
| | Query: Query by partition key + optional sort key | |
| | Scan: Read all items in table/index | |
| | | |
| | Query Parameters: | |
| | - KeyConditionExpression | |
| | - FilterExpression | |
| | - ProjectionExpression | |
| | - Limit | |
| | - ExclusiveStartKey (pagination) | |
| | | |
| +----------------------------------------------------------+ |
| |
| Conditional Writes |
| +----------------------------------------------------------+ |
| | | |
| | ConditionExpression: | |
| | - attribute_exists(attr) | |
| | - attribute_not_exists(attr) | |
| | - attr = value | |
| | - attr < value | |
| | | |
| | Use Cases: | |
| | - Prevent overwrites | |
| | - Optimistic locking | |
| | | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

Exam Tip

  1. Capacity Modes: On-demand (pay per request), Provisioned (RCU/WCU)
  2. RCU: 1 RCU = 1 strongly consistent read (4 KB)
  3. WCU: 1 WCU = 1 write (1 KB)
  4. GSI: Different partition key, separate capacity
  5. LSI: Same partition key, different sort key, created at table creation
  6. Streams: 24-hour retention, triggers Lambda
  7. Global Tables: Multi-region, multi-active, requires streams
  8. DAX: In-memory cache, microsecond latency
  9. TTL: Automatic item expiration
  10. Conditional Writes: Optimistic locking, prevent overwrites

Chapter 24: Amazon ElastiCache - In-Memory Caching


Last Updated: February 2026