Database Services
RDS, Aurora, DynamoDB selection criteria and when NOT to use managed databases
AWS Database Services
Master AWS database services with free flashcards and spaced repetition practice to reinforce your learning. This lesson covers Amazon RDS, DynamoDB, Aurora, and other managed database solutionsβessential concepts for building scalable, highly available data layers in the cloud. Whether you're preparing for AWS certifications or architecting production systems, understanding when and how to use each database service is crucial for success.
Welcome to AWS Database Services π»
AWS offers a comprehensive suite of managed database services that eliminate the operational overhead of running databases while providing enterprise-grade performance, availability, and security. Instead of provisioning servers, installing database software, applying patches, and managing backups manually, you can leverage AWS-managed services that handle these tasks automatically.
In this lesson, you'll learn the characteristics, use cases, and key features of AWS's primary database offerings. We'll explore relational databases (RDS, Aurora), NoSQL solutions (DynamoDB, DocumentDB), in-memory caches (ElastiCache), and specialized databases for specific workloads. By the end, you'll be able to select the appropriate database service for your application requirements.
Core Concepts π―
Amazon RDS (Relational Database Service)
Amazon RDS is a managed relational database service that supports six popular database engines:
| Engine | Use Case | Key Feature |
|---|---|---|
| MySQL | Web applications | Open source, wide adoption |
| PostgreSQL | Complex queries, JSON | Advanced data types |
| MariaDB | MySQL alternative | Enhanced performance |
| Oracle | Enterprise applications | BYOL licensing |
| SQL Server | Microsoft stack | .NET integration |
| Aurora | Cloud-native performance | 5x faster than MySQL |
Key RDS Features:
- π Automated Backups: Point-in-time recovery with retention up to 35 days
- π Multi-AZ Deployments: Synchronous replication to a standby instance in another Availability Zone for high availability
- π Read Replicas: Asynchronous replication for scaling read-heavy workloads (up to 15 replicas for Aurora, 5 for other engines)
- π§ Automated Patching: Database engine updates applied during maintenance windows
- π Vertical Scaling: Change instance types with minimal downtime
- π Encryption: At-rest encryption using AWS KMS, in-transit using SSL/TLS
Multi-AZ vs Read Replicas:
MULTI-AZ DEPLOYMENT (High Availability) βββββββββββββββββββββββββββββββββββββββββββ β AZ-1 (us-east-1a) β AZ-2 (us-east-1b)β β β β β ββββββββββββ β ββββββββββββ β β β PRIMARY ββββββββΌββββ STANDBY β β β β Instance β Sync β β Instance β β β ββββββ¬ββββββ β ββββββββββββ β β β β β β βΌ β (No reads) β β App writes β Auto-failover β β App reads β if primary failsβ βββββββββββββββββββββββββββββββββββββββββββ READ REPLICAS (Scale Reads) βββββββββββββββββββββββββββββββββββββββββββ β ββββββββββββ β β β PRIMARY β β β β Instance β β β ββββββ¬ββββββ β β β Async replication β β ββββββββββΌβββββββββ¬βββββββββ β β βΌ βΌ βΌ βΌ β β βββββββ βββββββ βββββββ βββββββ β β β RR1 β β RR2 β β RR3 β β RR4 β β β βββββββ βββββββ βββββββ βββββββ β β β² β² β² β² β β β β β β β β Read Read Read Read β β Traffic distributed across replicas β βββββββββββββββββββββββββββββββββββββββββββ
π‘ Pro Tip: Multi-AZ is for disaster recovery (automatic failover), while Read Replicas are for performance (distributing read load). You can use both together!
Amazon Aurora β‘
Aurora is AWS's cloud-native relational database built for the cloud. It's fully compatible with MySQL and PostgreSQL but delivers significantly better performance and availability.
Aurora Architecture:
ββββββββββββββββββββββββββββββββββββββββββββββββββ β AURORA CLUSTER β ββββββββββββββββββββββββββββββββββββββββββββββββββ€ β β β βββββββββββββββ βββββββββββββββ β β β PRIMARY βββββββββββ REPLICA β β β β Instance β β Instance β β β β (Read/Write)β β (Read Only) β β β ββββββββ¬βββββββ ββββββββ¬βββββββ β β β β β β βββββββββββββ¬ββββββββββββ β β βΌ β β βββββββββββββββββββββββββ β β β SHARED STORAGE β β β β - 6 copies across β β β β 3 AZs β β β β - Auto-healing β β β β - Auto-scaling β β β β - 128TB max β β β βββββββββββββββββββββββββ β ββββββββββββββββββββββββββββββββββββββββββββββββββ
Aurora Key Features:
- π Performance: Up to 5x faster than MySQL, 3x faster than PostgreSQL
- πΎ Storage Auto-Scaling: Automatically grows from 10GB to 128TB in 10GB increments
- π Continuous Backup: Backs up data continuously to S3 with point-in-time recovery
- β‘ Fast Cloning: Create a clone in minutes without copying data (copy-on-write)
- π Global Database: One primary region with up to 5 secondary regions, <1 second replication lag
- π‘ Serverless: Aurora Serverless automatically adjusts capacity based on demand
Aurora vs Standard RDS:
| Feature | Aurora | Standard RDS |
|---|---|---|
| Storage | Shared cluster volume | EBS volumes per instance |
| Read Replicas | Up to 15 | Up to 5 |
| Failover Time | < 30 seconds | 1-2 minutes |
| Storage Max | 128 TB | 64 TB (SQL Server 16TB) |
| Backup Storage | No additional cost | Charged beyond instance size |
| Cost | ~20% more | Lower starting price |
Amazon DynamoDB ποΈ
DynamoDB is AWS's fully managed NoSQL database service designed for high-performance applications requiring single-digit millisecond latency at any scale.
DynamoDB Data Model:
// DynamoDB stores items (similar to rows) in tables
{
"UserId": "user123", // Partition Key (required)
"Timestamp": "2024-01-15T10:30:00", // Sort Key (optional)
"Name": "Alice Johnson",
"Email": "alice@example.com",
"Orders": 47,
"Premium": true
}
Key DynamoDB Concepts:
- π Partition Key: Primary key that determines which partition stores the item (must be unique if no sort key)
- π Sort Key: Optional secondary key that orders items with the same partition key
- π Capacity Modes:
- On-Demand: Pay per request, automatic scaling (good for unpredictable workloads)
- Provisioned: Specify read/write capacity units (RCU/WCU), lower cost for steady traffic
- π Indexes:
- GSI (Global Secondary Index): Different partition/sort keys, queries across entire table
- LSI (Local Secondary Index): Same partition key, different sort key, must be created at table creation
- πΎ DynamoDB Streams: Capture time-ordered item-level changes for triggering Lambda functions
- π Global Tables: Multi-region, multi-active replication for global applications
DynamoDB Access Patterns:
QUERY vs SCAN ββββββββββββββββββββββββββββββββββββββββ β QUERY (Efficient) β β ββββββββββββββββββββββββββββββββββββββββ€ β Uses partition key + optional β β sort key condition β β β β SELECT * FROM Orders β β WHERE UserId = 'user123' β β AND OrderDate > '2024-01-01' β β β β Only reads matching items β β Low latency, predictable cost β ββββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββββ β SCAN (Expensive) β οΈ β ββββββββββββββββββββββββββββββββββββββββ€ β Reads every item in table β β β β SELECT * FROM Orders β β WHERE TotalAmount > 100 β β β β Reads entire table, filters after β β High latency, consumes all RCUs β β Use only for small tables or β β infrequent operations β ββββββββββββββββββββββββββββββββββββββββ
π‘ Design Tip: Design your partition keys to distribute traffic evenly. Avoid "hot partitions" where one key receives disproportionate traffic.
Amazon ElastiCache β‘
ElastiCache is a fully managed in-memory caching service supporting two engines:
Redis vs Memcached:
| Feature | Redis | Memcached |
|---|---|---|
| Data Types | Strings, lists, sets, sorted sets, hashes | Simple key-value strings |
| Persistence | β Optional disk persistence | β In-memory only |
| Replication | β Multi-AZ with automatic failover | β No replication |
| Backup/Restore | β Snapshots supported | β Not available |
| Multi-threading | β Single-threaded | β Multi-threaded |
| Use Case | Complex data, pub/sub, leaderboards | Simple caching, session storage |
Common Caching Patterns:
LAZY LOADING (Cache-Aside) ββββββββββββββββββββββββββββββββββββββ β 1. App requests data β β β β β 2. Check cache β β ββ Hit? Return cached data β β β ββ Miss? β β β 3. Query database β β β β β 4. Write to cache β β β β β 5. Return data β ββββββββββββββββββββββββββββββββββββββ WRITE-THROUGH ββββββββββββββββββββββββββββββββββββββ β 1. App writes data β β β β β 2. Write to cache first β β β β β 3. Write to database β β β β β 4. Confirm write β β β β Keeps cache always current but β β adds latency to writes β ββββββββββββββββββββββββββββββββββββββ
Other AWS Database Services π―
Amazon DocumentDB (MongoDB-compatible)
- Managed document database for JSON workloads
- Compatible with MongoDB 3.6, 4.0, 5.0 APIs
- Scales storage automatically up to 64TB
- Use case: Content management, catalogs, user profiles
// DocumentDB Query Example (MongoDB-compatible)
db.products.find({
category: "electronics",
price: { $lt: 500 }
}).sort({ rating: -1 }).limit(10)
Amazon Neptune (Graph Database)
- Supports both Property Graph (Gremlin) and RDF (SPARQL) models
- Highly optimized for traversing relationships
- Use case: Social networks, fraud detection, recommendation engines
// Gremlin query: Find friends of friends
g.V().hasLabel('person')
.has('name', 'Alice')
.out('knows')
.out('knows')
.dedup()
.values('name')
Amazon Keyspaces (Cassandra-compatible)
- Serverless, managed Apache Cassandra service
- Single-digit millisecond latency at any scale
- Use case: Time-series data, IoT applications
Amazon Timestream (Time-Series Database)
- Purpose-built for IoT and operational analytics
- Automatic data lifecycle management (hot/cold storage)
- 1000x faster and 1/10th cost of relational databases for time-series
Amazon QLDB (Quantum Ledger Database)
- Immutable, cryptographically verifiable transaction log
- Use case: Financial transactions, supply chain, regulatory compliance
CHOOSING THE RIGHT DATABASE βββββββββββββββββββββββββββββββββββββββββββββββ β Need ACID transactions + SQL? β β ββ Yes β RDS or Aurora β β ββ No β β β β β Need millisecond latency at scale? β β ββ Yes β DynamoDB β β ββ No β β β β β Working with graph relationships? β β ββ Yes β Neptune β β ββ No β β β β β Time-series/IoT data? β β ββ Yes β Timestream β β ββ No β β β β β Need MongoDB compatibility? β β ββ Yes β DocumentDB β β ββ No β β β β β Need immutable audit trail? β β ββ Yes β QLDB β βββββββββββββββββββββββββββββββββββββββββββββββ
Real-World Examples π
Example 1: E-Commerce Platform Architecture
A large e-commerce company uses multiple AWS database services for different parts of their application:
## Product catalog stored in DynamoDB for fast lookups
import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('ProductCatalog')
## Get product details - single-digit millisecond response
response = table.get_item(
Key={
'ProductId': 'PROD-12345',
'Category': 'Electronics'
}
)
product = response['Item']
## Order history in Aurora MySQL for complex analytics
import pymysql
connection = pymysql.connect(
host='myaurora.cluster-xxxxx.us-east-1.rds.amazonaws.com',
user='admin',
password='password',
database='orders'
)
with connection.cursor() as cursor:
# Complex join query for customer order history
sql = """
SELECT o.order_id, o.total, oi.product_id, oi.quantity
FROM orders o
JOIN order_items oi ON o.order_id = oi.order_id
WHERE o.customer_id = %s
AND o.order_date > DATE_SUB(NOW(), INTERVAL 6 MONTH)
ORDER BY o.order_date DESC
"""
cursor.execute(sql, ('CUST-67890',))
results = cursor.fetchall()
## Session data in ElastiCache Redis for fast access
import redis
redis_client = redis.Redis(
host='my-elasticache.xxxxx.cache.amazonaws.com',
port=6379,
decode_responses=True
)
## Store shopping cart with 1-hour expiration
redis_client.setex(
f"cart:{session_id}",
3600,
json.dumps(cart_items)
)
## Product recommendations using Neptune graph
from gremlin_python.driver import client
gremlin_client = client.Client(
'wss://my-neptune.cluster-xxxxx.neptune.amazonaws.com:8182/gremlin',
'g'
)
## Find products frequently bought together
query = """
g.V().has('product', 'id', 'PROD-12345')
.in('purchased_with')
.groupCount()
.order(local).by(values, desc)
.limit(local, 5)
"""
recommendations = gremlin_client.submit(query).all().result()
Why this architecture?
- DynamoDB: Product catalog needs fast reads at massive scale
- Aurora: Order history requires complex SQL joins and transactions
- ElastiCache: Session data needs sub-millisecond access
- Neptune: Recommendation engine traverses purchase relationships
Example 2: Multi-Region Global Application
## Setting up DynamoDB Global Tables for worldwide access
import boto3
## Create table in primary region (us-east-1)
dynamodb_us = boto3.client('dynamodb', region_name='us-east-1')
dynamodb_us.create_table(
TableName='GlobalUserProfiles',
KeySchema=[
{'AttributeName': 'UserId', 'KeyType': 'HASH'}
],
AttributeDefinitions=[
{'AttributeName': 'UserId', 'AttributeType': 'S'}
],
BillingMode='PAY_PER_REQUEST',
StreamSpecification={
'StreamEnabled': True,
'StreamViewType': 'NEW_AND_OLD_IMAGES'
}
)
## Add replica regions
dynamodb_us.update_table(
TableName='GlobalUserProfiles',
ReplicaUpdates=[
{
'Create': {
'RegionName': 'eu-west-1'
}
},
{
'Create': {
'RegionName': 'ap-southeast-1'
}
}
]
)
## Writes in any region replicate to all regions
table = boto3.resource('dynamodb', region_name='eu-west-1').Table('GlobalUserProfiles')
table.put_item(
Item={
'UserId': 'user-europe-001',
'Name': 'Emma Schmidt',
'Email': 'emma@example.com',
'PreferredLanguage': 'de'
}
)
## This write is automatically replicated to us-east-1 and ap-southeast-1
## Users in all regions see consistent data with <1 second replication lag
Example 3: Aurora Serverless Auto-Scaling
## Aurora Serverless automatically scales based on load
import boto3
import pymysql
## Configuration for Aurora Serverless v2
rds = boto3.client('rds')
## Create Aurora Serverless v2 cluster
response = rds.create_db_cluster(
DBClusterIdentifier='my-serverless-cluster',
Engine='aurora-mysql',
EngineVersion='8.0.mysql_aurora.3.02.0',
ServerlessV2ScalingConfiguration={
'MinCapacity': 0.5, # Minimum ACUs (Aurora Capacity Units)
'MaxCapacity': 16 # Maximum ACUs
},
MasterUsername='admin',
MasterUserPassword='MySecurePassword123!',
DatabaseName='myappdb'
)
## Application code - no capacity management needed
def process_batch_job():
connection = pymysql.connect(
host='my-serverless-cluster.cluster-xxxxx.us-east-1.rds.amazonaws.com',
user='admin',
password='MySecurePassword123!',
database='myappdb'
)
with connection.cursor() as cursor:
# Heavy query - Aurora automatically scales up
cursor.execute("""
INSERT INTO analytics_summary
SELECT
DATE(order_date) as date,
category,
COUNT(*) as order_count,
SUM(total_amount) as revenue
FROM orders
WHERE order_date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
GROUP BY DATE(order_date), category
""")
connection.commit()
connection.close()
# Aurora automatically scales down when idle - you only pay for what you use
Benefits:
- Scales from 0.5 to 16 ACUs automatically
- No over-provisioning waste
- Handles unpredictable workloads
- Cost-effective for intermittent usage
Example 4: RDS Read Replica Scaling
## Using read replicas to scale a read-heavy application
import boto3
import random
class DatabaseConnection:
def __init__(self):
# Primary instance for writes
self.primary_endpoint = 'mydb.xxxxx.us-east-1.rds.amazonaws.com'
# Read replica endpoints
self.read_replicas = [
'mydb-replica-1.xxxxx.us-east-1.rds.amazonaws.com',
'mydb-replica-2.xxxxx.us-east-1.rds.amazonaws.com',
'mydb-replica-3.xxxxx.us-east-1.rds.amazonaws.com'
]
def get_write_connection(self):
# All writes go to primary
return pymysql.connect(
host=self.primary_endpoint,
user='admin',
password='password',
database='production'
)
def get_read_connection(self):
# Load balance reads across replicas
replica_host = random.choice(self.read_replicas)
return pymysql.connect(
host=replica_host,
user='admin',
password='password',
database='production'
)
## Application usage
db = DatabaseConnection()
## Write operation - goes to primary
def create_order(customer_id, items):
conn = db.get_write_connection()
with conn.cursor() as cursor:
cursor.execute(
"INSERT INTO orders (customer_id, total) VALUES (%s, %s)",
(customer_id, sum(item['price'] for item in items))
)
conn.commit()
conn.close()
## Read operation - distributed across replicas
def get_customer_orders(customer_id):
conn = db.get_read_connection() # Random replica selected
with conn.cursor() as cursor:
cursor.execute(
"SELECT * FROM orders WHERE customer_id = %s ORDER BY created_at DESC",
(customer_id,)
)
results = cursor.fetchall()
conn.close()
return results
Architecture Benefits:
- Distributes read load across multiple instances
- Primary handles all writes
- Can add up to 5 replicas (15 for Aurora)
- Eventual consistency (~few seconds lag)
Common Mistakes β οΈ
1. Using Scan Instead of Query in DynamoDB
β Wrong:
## Scans entire table - expensive and slow!
response = table.scan(
FilterExpression='UserId = :uid',
ExpressionAttributeValues={':uid': 'user123'}
)
β Correct:
## Query using partition key - fast and efficient
response = table.query(
KeyConditionExpression='UserId = :uid',
ExpressionAttributeValues={':uid': 'user123'}
)
Why it matters: Scan reads every item and consumes capacity units for the entire table, even if you only need one item. Query only reads matching items.
2. Not Using Connection Pooling with RDS
β Wrong:
## Creating new connection for each request
def get_user(user_id):
conn = pymysql.connect(host='...', user='...', password='...')
# Query...
conn.close()
# Opens and closes connections repeatedly - slow!
β Correct:
## Use connection pooling
from sqlalchemy import create_engine, pool
engine = create_engine(
'mysql+pymysql://admin:password@mydb.xxxxx.rds.amazonaws.com/mydb',
poolclass=pool.QueuePool,
pool_size=10,
max_overflow=20
)
def get_user(user_id):
with engine.connect() as conn:
result = conn.execute("SELECT * FROM users WHERE id = %s", user_id)
# Connection returned to pool, not closed
3. Ignoring Multi-AZ for Production RDS
β Wrong: Running production database in single AZ to save costs
β Correct: Always enable Multi-AZ for production workloads
rds.create_db_instance(
DBInstanceIdentifier='production-db',
DBInstanceClass='db.r5.large',
Engine='postgres',
MultiAZ=True, # Essential for production!
BackupRetentionPeriod=7,
PreferredBackupWindow='03:00-04:00'
)
Why: Hardware failures happen. Multi-AZ provides automatic failover with minimal downtime (1-2 minutes).
4. Not Monitoring Database Performance Metrics
β Wrong: Waiting until users complain about slow queries
β Correct: Set up CloudWatch alarms for key metrics
cloudwatch = boto3.client('cloudwatch')
## Alert when CPU exceeds 80%
cloudwatch.put_metric_alarm(
AlarmName='RDS-High-CPU',
MetricName='CPUUtilization',
Namespace='AWS/RDS',
Statistic='Average',
Period=300,
EvaluationPeriods=2,
Threshold=80.0,
ComparisonOperator='GreaterThanThreshold',
Dimensions=[{'Name': 'DBInstanceIdentifier', 'Value': 'production-db'}]
)
## Alert when DynamoDB throttling occurs
cloudwatch.put_metric_alarm(
AlarmName='DynamoDB-Throttles',
MetricName='UserErrors',
Namespace='AWS/DynamoDB',
Statistic='Sum',
Period=60,
EvaluationPeriods=1,
Threshold=10.0,
ComparisonOperator='GreaterThanThreshold',
Dimensions=[{'Name': 'TableName', 'Value': 'MyTable'}]
)
5. Poor DynamoDB Partition Key Design
β Wrong:
## Using date as partition key - creates hot partition!
table.put_item(
Item={
'Date': '2024-01-15', # Everyone writes to same partition today!
'EventId': 'event-123',
'Data': {...}
}
)
β Correct:
## Use high-cardinality attribute as partition key
table.put_item(
Item={
'EventId': 'event-123', # Unique partition key
'Timestamp': '2024-01-15T10:30:00', # Sort key
'Data': {...}
}
)
Rule of thumb: Choose partition keys that distribute traffic evenly. Avoid keys where most requests target the same value.
6. Forgetting to Enable Encryption
β Wrong: Creating database without encryption
β Correct: Always encrypt sensitive data
## RDS with encryption
rds.create_db_instance(
DBInstanceIdentifier='secure-db',
StorageEncrypted=True,
KmsKeyId='arn:aws:kms:us-east-1:123456789012:key/xxxxx',
# ... other parameters
)
## DynamoDB with encryption
dynamodb.create_table(
TableName='SecureData',
SSESpecification={
'Enabled': True,
'SSEType': 'KMS',
'KMSMasterKeyId': 'arn:aws:kms:us-east-1:123456789012:key/xxxxx'
},
# ... other parameters
)
Key Takeaways π―
π Quick Reference Card
| Service | Type | Best For | Key Feature |
|---|---|---|---|
| RDS | Relational | Traditional apps, ACID transactions | Multi-AZ failover |
| Aurora | Relational | High-performance SQL workloads | 5x MySQL performance |
| DynamoDB | NoSQL | Massive scale, low latency | Single-digit ms reads |
| ElastiCache | In-Memory | Caching, session storage | Sub-millisecond latency |
| DocumentDB | Document | JSON workloads | MongoDB compatible |
| Neptune | Graph | Relationship traversal | Gremlin & SPARQL |
| Timestream | Time-Series | IoT, metrics | Auto lifecycle mgmt |
Decision Framework:
- Need SQL + ACID? β RDS or Aurora
- Need NoSQL scale? β DynamoDB
- Need sub-ms caching? β ElastiCache
- Need graph queries? β Neptune
- Need time-series? β Timestream
- Need MongoDB API? β DocumentDB
- Need audit trail? β QLDB
Cost Optimization Tips:
π° Use Aurora Serverless for intermittent workloads π° Use DynamoDB on-demand for unpredictable traffic π° Use RDS Reserved Instances for steady workloads (up to 69% savings) π° Delete unused snapshots and replicas π° Right-size instances based on CloudWatch metrics
Security Checklist:
π Enable encryption at rest (KMS) π Enable encryption in transit (SSL/TLS) π Use IAM database authentication when possible π Never hardcode credentials (use Secrets Manager) π Enable VPC security groups and private subnets π Enable automated backups with sufficient retention π Enable CloudWatch Logs for audit trails
π Further Study
- AWS Database Documentation: https://docs.aws.amazon.com/databases/
- DynamoDB Best Practices: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/best-practices.html
- Aurora Performance Tuning: https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Aurora.BestPractices.html
π§ Memory Device - "RADE-NT":
- RDS - Relational Database Service
- Aurora - Cloud-native relational
- DynamoDB - NoSQL key-value
- ElastiCache - In-memory caching
- Neptune - Graph database
- Timestream - Time-series data
Master these six core services and you'll be equipped to design robust, scalable data architectures on AWS! π