Week 4 · System Design
From a simple application to a highly available architecture that can grow with demand.
Goal
A web application that can continue serving users even if an Availability Zone fails.
Important: user counts in this chapter are teaching examples, not hard AWS limits. Measure concurrency, RPS, latency, and data size.
1 · Start simple
Amazon Route 53 converts a domain name into the destination that should receive the request.
High availability
Do not start with every service at once. Add complexity when a real need appears.
2 · Frontend
Amplify builds, deploys, and globally delivers the frontend. The backend stays a separate set of application services.
Amplify workflow
Amplify delivers the frontend. After the page loads, the browser calls the backend API directly.
Amplify trade-offs
3 · Backend compute
There is no single best option. It depends on control, containers, runtime length, and operational complexity.
Compare
Max control → EC2. Containers without Kubernetes → ECS/Fargate. Need Kubernetes → EKS. Short-lived events → Lambda.
4 · API layer
Authenticate, route, throttle, and decide which backend service should handle each request.
API choices
REST/HTTP/serverless → API Gateway. EC2 or containers → ALB. GraphQL or real-time → AppSync.
5 · Database
High traffic alone is not a reason to move to NoSQL. Relationships, joins, constraints, and ACID transactions usually point to SQL first.
NoSQL
Do not choose NoSQL only because of terabytes of data or thousands of writes per second.
6 · Aurora
Aurora keeps the SQL model but separates compute from distributed Multi-AZ storage. Read replicas scale reads; a replica can be promoted if the writer fails.
Think of Aurora as: managed SQL + distributed storage + easier read scaling + high availability.
Data layer tools
Aurora Serverless v2 can adjust compute for variable traffic — but it cannot fix an inefficient query.
7 · Growth
Route 53 → Amplify → Fargate → Aurora Serverless v2 can go far if designed well. Bottlenecks become more visible as usage grows.
8 · Frontend scale
Good scaling often comes from doing less work, not from adding more servers.
9 · Connections
When Fargate or Lambda scales out, each instance may open database connections. The database can choke on connection management even when CPU looks healthy.
RDS Proxy pools connections. It does not make slow SQL fast, and it does not replace read replicas.
10 · Cache
Check the cache first. On a miss, query the database and store the result. The new problem is cache invalidation.
11 · Architecture
Product complexity, deployment risk, team ownership, and failure isolation matter as much as traffic.
Extract a microservice for independent scaling, ownership, or failure isolation — not because a user count was reached.
12 · Decouple
SQS = wait · SNS = broadcast · EventBridge = route · Kinesis = stream
13 · Microservices
One service may use Aurora, another DynamoDB, another SQS or EventBridge. That is purpose-built services.
14 · Massive scale
15 · Closing
Start simple. Measure real bottlenecks. Use managed services where they fit. Cache aggressively when freshness allows it. Separate workloads only when you gain clear scaling, ownership, or failure-isolation benefits.
Good architecture evolves with evidence.