How to grow a system on Amazon Web Services without falling over, from the Well-Architected Framework to a full reference design. Each note links to the official AWS docs. Press play on any sketch to watch it happen.
Start with the foundations
1 The Well-Architected Framework
AWS sums up how to build good cloud systems in six pillars. Treat them as a review checklist: go through each one and ask how your workload measures up. Scaling mostly lives under Performance Efficiency and Reliability, but it affects all six.
Operational excellence: run and improve the system, with automation in place of manual steps.
Security: protect data and access, in every layer.
Reliability: recover from failure and keep working as demand changes.
Performance efficiency: use resources well as your needs grow.
Cost optimization: avoid paying for what you do not use.
Sustainability: reduce the energy and hardware your workload needs.
Concept map
1/6 Operational excellence: can you deploy and fix things without manual heroics?
Rule of thumb: Every pillar trades against another. Adding redundancy raises reliability and raises the bill.
AWS is divided into Regions around the world, and each Region contains several Availability Zones: separate groups of data centres with their own power and networking. Spreading a system across zones is the cheapest big reliability win on AWS.
Region: a geographic area, such as Singapore or Ireland. Choose one close to your users.
Availability Zone: an isolated location inside a Region, close enough for very fast connections.
Multi-AZ: run in at least two zones so one failure does not take you offline.
Multi-Region: much harder and more expensive. Keep it for strict uptime or legal needs.
Deployment diagram
1/5 The load balancer spreads traffic across app servers in two separate zones.
Rule of thumb: Run everything important in at least two Availability Zones from the start.
The cheapest request is the one that never reaches your servers. Route 53 answers DNS, CloudFront caches content at edge locations near users, and S3 stores your files.
Amazon Route 53: DNS that can route by health, latency or weight.
Amazon CloudFront: a CDN that serves cached content from locations close to each user.
Amazon S3: object storage for images, downloads and whole static sites, with no servers to run.
Offloading: moving images and files out of your app lets it scale far further for the same cost.
Data flow diagram
1/5 The browser asks Route 53 where the site lives.
Rule of thumb: Serve every static file through CloudFront before you think about adding servers.
A load balancer sits in front of your servers and spreads requests across them. It also runs health checks, so traffic stops going to a server that has died. AWS runs it for you, across zones.
Application Load Balancer: works at layer 7, reads HTTP, and routes by path or host.
Network Load Balancer: works at layer 4 for very high throughput and low latency.
Target group: the set of servers or containers that receive the traffic.
Health checks: regular requests to each target. Failing targets are taken out of rotation.
Deployment diagram
1/5 Requests arrive and get shared across all three servers.
Rule of thumb: Make the health check a real endpoint that proves your app can do its job.
Auto Scaling adds servers when demand rises and removes them when it falls, so you pay for what you use and survive traffic spikes. It needs your app to be stateless, so that any server can handle any request.
Auto Scaling group: a fleet of EC2 instances with a minimum, a maximum and a desired size.
Target tracking: you pick a target, such as 50% average CPU, and AWS adds or removes instances to hold it.
Launch template: the recipe each new instance is built from.
Stateless servers: keep sessions in ElastiCache or DynamoDB and files in S3, because any instance can disappear.
Scaling up first: a larger instance needs no code change, but every instance size has a limit.
Deployment diagram
1/5 A quiet morning: two instances, CPU at a comfortable 45%.
Rule of thumb: Set a sensible maximum so a bug or an attack cannot scale your bill without limit.
Containers package your app with everything it needs, so it runs the same everywhere. AWS has two main ways to run them, plus an option that removes the servers from view.
Amazon ECR: a private registry where your container images are stored.
Amazon ECS: the AWS container orchestrator. Simpler, and a good default on AWS.
Amazon EKS: managed Kubernetes. Pick this when you need Kubernetes or already know it.
AWS Fargate: runs containers for ECS or EKS with no EC2 instances to manage.
Deployment diagram
1/5 You push a new image to ECR and ask for three running copies.
Rule of thumb: Choose ECS with Fargate unless you have a clear reason to need Kubernetes.
Lambda runs your code in response to events, with nothing to provision. Pair it with API Gateway and DynamoDB, and you get a whole backend that scales up on its own and costs almost nothing when idle.
AWS Lambda: runs a function per request or event. Each run can last up to 15 minutes.
Amazon API Gateway: gives your functions an HTTP front door.
Concurrency: each request gets its own environment, so extra load means extra copies. Account limits still apply.
Cold start: the extra delay when a new environment has to start.
Data flow diagram
1/5 Nobody is using the app, so nothing is running.
Rule of thumb: Watch how many database connections your functions open. A relational database cannot take thousands at once.
If one part of a system must wait for another, a slowdown spreads. Queues and topics put a buffer in the middle, so a traffic spike becomes a backlog instead of an outage.
Amazon SQS: a queue. Each message is handled by one consumer. Standard queues deliver at least once, so consumers must be safe to run twice.
Amazon SNS: publish/subscribe. One message fans out to every subscriber.
Amazon EventBridge: an event bus that routes events by rules.
Dead-letter queue: messages that keep failing are parked for inspection instead of blocking the rest.
Data flow diagram
1/5 The app publishes one message and gets on with its work.
Rule of thumb: Ask whether the user needs the result right now. If not, put it on a queue.
A cache keeps a copy of expensive results in memory. Done well, it cuts latency and takes load off your database. Done badly, it serves stale data with great confidence.
Amazon ElastiCache: managed in-memory caching with engines such as Valkey and Redis OSS.
DynamoDB Accelerator: DAX is an in-memory cache built specifically for DynamoDB.
Cache-aside: check the cache, read the database on a miss, then store the result.
Eviction: LRU drops the least recently used entry when full. A TTL expires entries after a set time.
Data flow diagram
1/5 The app wants a product page, so it checks the cache first.
Rule of thumb: Invalidation is the hard part. Give every entry a TTL, even when you also delete it on write.
Amazon RDS runs relational databases for you. Two separate features are often confused: Multi-AZ is for surviving failure, and read replicas are for handling more reads.
Multi-AZ: keeps a synchronous standby in another zone and fails over automatically. It is for availability.
Read replicas: asynchronous copies that take read traffic. They are for scale, and they can lag.
Amazon Aurora: a MySQL and PostgreSQL compatible database with shared storage across zones and up to 15 read replicas.
Connection pooling: RDS Proxy shares connections, which helps when Lambda or many instances connect at once.
Deployment diagram
1/5 All writes go to the primary.
Rule of thumb: Multi-AZ protects you. Read replicas speed you up. Most production systems need the first before the second.
DynamoDB is a key-value and document database built to stay fast at any size. It spreads data across partitions by hashing your partition key, so the design of that key decides how well it scales.
Partition key: decides which partition holds an item. Choose one with many distinct values.
Hot partition: one popular key can overload its partition however large the table is.
On-demand mode: pay per request and let the table absorb traffic changes.
Access patterns: design tables around your queries up front, because joins do not exist here.
Data flow diagram
1/4 Saving user-17: the key is hashed, and the hash picks partition 2.
Rule of thumb: Write down your queries before you design the table. With DynamoDB, the order is reversed.
You do not build all of this on day one. A scalable AWS system usually grows in stages, each one fixing the bottleneck you actually have. Watch one app grow from a single server.
Stage 1: one EC2 instance and a managed database. Fine for your first users.
Stage 2: a load balancer and an Auto Scaling group across two zones.
Stage 3: CloudFront and S3 for files, ElastiCache for repeated reads.
Stage 4: read replicas for the database and SQS for slow background work.
Deployment diagram
1/4 Stage 1: one server and a database. Simple, cheap and enough for now.
Rule of thumb: Measure first, then fix the one bottleneck you can prove. The rest can wait.