cerf
Three-tier reference architecture

Three-tier reference architecture

The three-tier web app, done properly

ALB, Auto Scaling across AZs, RDS Multi-AZ, and CloudFront on top, because half the associate exam is this one diagram and the places it can fall over.

Why this shape keeps showing up

The Well-Architected reliability pillar opens with the observation that reliability is hard on premises for three specific reasons: single points of failure, lack of automation, and lack of elasticity. The three-tier reference architecture is AWS's standing answer to all three, which is why some version of it sits behind an enormous share of SAA-C03 questions. Presentation tier at the edge, application tier on load-balanced compute, data tier on a managed relational database. Each tier gets its own redundancy mechanism, and the seams between tiers are where exam questions live.

The unit of failure the whole design is built around is the Availability Zone. Every stateful and stateless layer is deployed across at least two AZs, and each layer has a different mechanism for surviving the loss of one. The Application Load Balancer distributes traffic across targets in multiple AZs and routes only to targets that pass health checks. The Auto Scaling group monitors instance health, replaces impaired instances to maintain desired capacity, and balances instances evenly across the AZs you give it. RDS Multi-AZ maintains a synchronous standby replica in a different AZ and fails over to it automatically.

Notice what each mechanism does NOT do. The ALB does not create new capacity; it only steers traffic away from unhealthy targets. The Auto Scaling group does not route traffic; it only maintains the fleet. The RDS standby does not serve any traffic at all until failover promotes it. Exam distractors routinely swap these responsibilities, so keep the division of labor sharp: ALB routes, ASG replaces and scales, Multi-AZ standby waits.

Three-tier topology: one redundancy mechanism per tier, spread across two AZs
Three-tier topology: one redundancy mechanism per tier, spread across two AZsAWS CloudGlobal edge networkus-east-1Application VPC 10.0.0.0/16Public subnets AZ-a + AZ-bAuto Scaling group min 2 / max 6, balanced per AZRDS Multi-AZ synchronous standbyApp subnet AZ-aApp subnet AZ-bDB subnet AZ-aDB subnet AZ-bDNS queryHTTPS 443static, on missdynamic originto load balancerhealth-checked targethealth-checked targetegressegressoutboundoutboundwrites + readswrites + readssynchronous replicationscale / replaceViewersglobal browsersRoute 53alias -> CloudFrontCloudFrontedge cacheS3static originInternetgatewayVPC edgeApplication LBinternet-facing, 2 …NAT gatewayAZ-aNAT gatewayAZ-bApp instanceAZ-aApp instanceAZ-bCloudWatchmetrics + healthRDS primaryAZ-a, tcp/3306RDS standbyAZ-b, no reads
Trace
The Availability Zone is the unit of failure. Presentation traffic enters through CloudFront and the internet gateway; the ALB spans both public subnets; the Auto Scaling group keeps stateless app instances balanced across two private-subnet AZs; and RDS Multi-AZ keeps a synchronous standby in the second AZ. CloudWatch watches metrics and status checks to drive scaling and replacement.

A request walks through

Follow one browser request end to end. First, DNS: Route 53 resolves the site's domain to the CloudFront distribution. CloudFront routes the request to the edge location with the lowest latency for that viewer. If the request is for a static object (CSS, JS, images) and the edge has it cached, the response never touches your VPC at all. On a miss, CloudFront fetches from the origin you configured for that path, typically an S3 bucket for static assets, caches it at the edge (24 hours by default, tunable from zero with no maximum), and serves it. This is the quiet workhorse of the design: the static tier absorbs most of the request volume so the expensive tiers only see dynamic traffic.

Dynamic requests get forwarded to a second origin, the internet-facing ALB in the public subnets. The ALB evaluates its listener rules in priority order and picks a target from the matched target group, round robin by default, or least outstanding requests if you configure it. Health checks are defined per target group, and only healthy targets receive traffic. The targets are EC2 instances in an Auto Scaling group spread across private subnets in two AZs. The integration between the two services is automatic and bidirectional: instances the ASG launches are registered with the target group, and instances it terminates are deregistered. When CloudWatch metrics breach a scaling policy threshold, the group launches or terminates instances between its min and max, keeping the fleet balanced across AZs as it grows and shrinks.

The app instance then talks to the data tier: an RDS Multi-AZ DB instance reached through a single DNS endpoint. Every write commits synchronously to both the primary and the standby replica in the other AZ, which is what makes failover lossless, and also why Multi-AZ deployments can show higher write and commit latency than Single-AZ. When the primary becomes unhealthy (impaired host, storage failure, network partition, an OS patch during the maintenance window, or a manual reboot-with-failover), RDS promotes the standby and repoints the instance's DNS record at it. Typical failover takes 60 to 120 seconds, and the application's only job is to reconnect: same endpoint name, new address underneath. That last step is a classic trap. A JVM that caches DNS lookups indefinitely will keep hammering the dead primary's IP forever, which is why AWS documents setting networkaddress.cache.ttl to 60 seconds or less.

A request walks through: DNS, edge cache, dynamic origin, and the RDS failover flip
A request walks through: DNS, edge cache, dynamic origin, and the RDS failover flipAWS CloudGlobal edgeus-east-1Application VPC 10.0.0.0/16Public subnets AZ-a + AZ-bAuto Scaling group targets in 2 AZsDB subnets AZ-a + AZ-bApp subnet AZ-aApp subnet AZ-b1. resolve domainalias to distribution2. HTTPS to edgecache miss: staticdynamic: forward to originlistener rule -> targetlistener rule -> targetmetrics -> scaleresolve endpointpoints to primarySQL read/writeSQL read/writesynchronous commitafter failover: repointedBrowserone viewerRoute 53alias recordCloudFrontdistributionEdge locationlowest latencyS3static originApplication LBlistener rulesApp instanceAZ-aApp instanceAZ-bCloudWatchscaling metricsRDS endpointsingle DNS nameRDS primaryAZ-aRDS standbyAZ-b, promoted on f…
Trace
Route 53 resolves to CloudFront, which serves cache hits at the nearest edge and forwards misses. Static misses go to S3; dynamic requests forward to the ALB, which picks a target from the Auto Scaling group. The app resolves the RDS endpoint, a single DNS name whose address is flipped from primary to standby during a 60 to 120 second failover.

What this teaches for the exam

For task 2.2 (highly available and fault-tolerant architectures), this pattern is the canonical answer to 'mitigate single points of failure.' Audit the diagram like the exam does: an ASG confined to one AZ, an ALB with all its instances in one subnet, or a Single-AZ RDS instance under a multi-AZ app tier are all availability bugs the correct answer fixes. Know the RDS Multi-AZ facts cold: synchronous replication, automatic failover in roughly 60 to 120 seconds via a DNS flip, failover triggered by host, storage, or network failure as well as planned OS maintenance, and no application code changes required beyond reconnecting. Just as important, know its limits: a Multi-AZ single-standby deployment is a high-availability feature, not a scaling feature, and the standby cannot serve reads. When a question wants read scaling, the answer is read replicas or a Multi-AZ DB cluster, not the standby.

For task 3.2 (high-performing and elastic compute), the ALB plus ASG pairing is the reference implementation of 'identify metrics and conditions to perform scaling actions.' Min, max, and desired capacity bound the fleet; scaling policies move desired capacity in response to demand; health checks (EC2 status checks, plus ELB health checks or custom checks when the app can fail while the OS stays healthy) trigger replacement rather than scaling. Offloading static content to CloudFront and S3 is itself an elasticity answer: it removes load from the compute tier entirely, which usually beats adding instances on both performance and cost.

Finally, use the pattern as a baseline for spotting what a question is really asking. If the scenario adds 'users lose their carts when an instance terminates,' the defect is state on instances and the fix is externalizing session state, not more AZs. If it says 'reads are overwhelming the database,' the fix is read replicas or a cache in front of RDS, not a bigger standby. If it says 'failover happened but the app kept erroring for hours,' think cached DNS. The three-tier diagram is rarely the whole question; it is the stage on which the actual fault is placed, and knowing the healthy version by heart is how you spot the broken piece quickly.

Reading the diagram for defects: externalized state, read scaling, and the cached-DNS trap
Reading the diagram for defects: externalized state, read scaling, and the cached-DNS trapAWS CloudCloudFront + S3 static offloadus-east-1Application VPCPublic subnetsAuto Scaling group (stateless tier)Data tierRDS Multi-AZ + read replicasHTTPSstatic offload (elasticity)dynamicround robinround robinsession statesession statecache-aside readson cache misswriteswritesread queriesread queriessynchronous (HA, no reads)async replicationasync replicationViewersbrowsersCloudFrontstatic offloadS3static assetsApplication LB2 AZsApp instanceAZ-a, statelessApp instanceAZ-b, statelessDynamoDBsession storeElastiCacheread cacheRDS primarywritesRDS standbyHA only, no readsRead replicaasync, read scalingRead replicaasync, read scaling
Trace
The exam places a fault on this stage. If instances lose carts on termination, the fix is externalizing session state (DynamoDB), not more AZs. If reads overwhelm the database, the fix is a cache in front of RDS and read replicas, not a bigger standby, which serves no reads. Offloading static content to CloudFront and S3 is itself an elasticity answer.

More diagrams

The three-tier reference architecture: CloudFront, ALB, Auto Scaling across AZs, RDS Multi-AZ
The three-tier reference architecture: CloudFront, ALB, Auto Scaling across AZs, RDS Multi-AZAWS CloudGlobal edgeus-east-1Application VPC 10.0.0.0/16Public subnets AZ-a + AZ-bAuto Scaling group min 2, balanced per AZDB subnets AZ-a + AZ-bPrivate subnet AZ-aPrivate subnet AZ-bDNS queryHTTPS 443static, on missdynamic, forwardedhealth checkswrites + readssync replicationUserbrowserRoute 53alias recordCloudFrontedge cacheS3 bucketstatic originApplication LBdynamic originApp serverAZ-aApp serverAZ-bRDS primaryAZ-a, tcp/3306RDS standbyAZ-b, no reads
Trace
CloudFront fronts both origins: static assets come from S3 and dynamic requests are forwarded to the internet-facing ALB. Behind the ALB an Auto Scaling group keeps instances balanced across two Availability Zones, and RDS Multi-AZ keeps a synchronous standby ready in the second AZ. The standby serves no traffic until failover flips the database DNS endpoint.

Sources

Practice what you just read

6 questions from this architecture

Loading…