100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Multi-Cloud Architecture & Serverless
55 minadvanced

Practice — design a multi-region active-active architecture

This practice exercise applies the networking concepts from Module 1 to a realistic design challenge. You will architect a globally available scorecard platform that serves IPL match data to viewers across India, Southeast Asia, and the UK with sub-200ms latency, zero-downtime deployments, and automatic regional failover. The scenario integrates every major service covered so far: Route 53, CloudFront, ALB, VPC networking, and the AWS Well-Architected Framework.

Analogy🏏Cricket
🏏 Think of it like cricket: In Test cricket, the ICC publishes playing conditions — governing over rates, DRS quotas, pitch inspection protocols, and player conduct — that both captains sign before the first session, whether the match is at Lord’s, the MCG, or Eden Gardens. Just as the playing conditions give umpires a single authoritative standard so every ruling references the same document rather than personal judgement, the Well-Architected Framework gives architects a shared evaluation language so every workload is measured against the same six pillars rather than each engineer’s intuition. Just as a team posting a slow over rate incurs penalties regardless of their score, a workload with Security or Reliability gaps carries structural risk regardless of how quickly it shipped. Just as every specialist role — opener, keeper, tail — has defined performance expectations against which selectors evaluate each player, every workload component is evaluated against pillar-specific best-practice questions. This reveals why the framework must precede any advanced architectural decision: a shared, evidence-based standard transforms subjective trade-offs into structured, auditable risk assessments that hold across teams, accounts, and regions.

An active-active architecture runs the full application stack in two or more AWS regions simultaneously, with all regions serving live traffic at all times. This is distinct from active-passive, where the secondary region only receives traffic after the primary fails. Active-active requires all regions to share state, route traffic intelligently based on proximity, and handle partial failures gracefully without a global failover event that disrupts all users simultaneously.

Work through each design task in sequence. For each task, sketch the architecture first, then validate it against the Well-Architected Framework pillar most relevant to that task: Reliability for failover design, Performance Efficiency for latency routing, Cost Optimization for CDN caching, and Security for cross-region access controls. The exercise ends with two quiz questions that test your ability to apply the design principles to novel failure scenarios.

Scenario

The IPL Scorecard Platform serves live match data, player statistics, and video highlights to 8 million concurrent viewers during finals matches. The platform currently runs in ap-south-1 (Mumbai) only. After a scheduled maintenance window caused a two-hour outage during a semi-final, the product team requires a multi-region architecture that can survive a complete regional failure without any manual operator intervention and with a maximum data loss window of 60 seconds.

Analogy🏏Cricket
🏏 Think of it like cricket: this resize scenario is like the media crew on a busy match day handling a predictable flow of highlight stills with sudden bursts during a collapse. Just as the IPL media team uploads about 500 images per match day, each 8 MB, needing broadcast, web, and mobile variants within 30 seconds, the crew shoots a steady stream of key moments that must hit the big screen, website, and app almost immediately. Just as the pipeline must absorb occasional bursts of 50 to 100 images when wickets tumble in a cluster, the crew faces a flurry of must-capture frames during a dramatic middle-order collapse and cannot drop any. The 30-second processing target is like the rule that a replay must reach the screen before the next ball is bowled. The payoff: like a crew sized for the steady rhythm yet ready for a sudden rush, the design must meet the everyday load cheaply while scaling instantly through a burst without losing a single frame.

The application has three distinct traffic profiles that require different architectural treatment. Live score API endpoints at /api/scores/* are write-heavy during matches, with updates every 3 seconds from stadium data feeds, and must be strongly consistent across regions. Player statistics at /api/players/* are read-heavy and can tolerate 60-second eventual consistency. Static assets at /static/* including team logos and UI components never change during a match and can be cached aggressively for 24 hours.

The engineering team has eight weeks to deliver the first milestone: multi-region read availability with automatic DNS failover. Full active-active write consistency using DynamoDB Global Tables is scheduled for the second milestone. This practice exercise focuses on the networking and DNS layer of the first milestone: designing the traffic routing, health check, and CDN caching architecture that makes both milestones operationally sound.

Architecture Requirements

  • Deploy the application stack in ap-south-1 (primary) and ap-southeast-1 (secondary) with identical infrastructure in both regions.
  • Route 53 latency routing directs each viewer to the closest healthy region; health checks use calculated checks aggregating three AZ-level checks per region with a threshold of 2 of 3.
  • CloudFront distribution with three cache behaviours: /api/scores/* with CachingDisabled and Lambda@Edge JWT validation, /api/players/* with 60-second TTL, and /static/* with 86400-second TTL.
  • ALB in each region uses path-based routing to separate the scores microservice and the players microservice into independent target groups, enabling independent scaling and independent health check evaluation.
  • VPC design uses Transit Gateway in each region with a dedicated inspection VPC hosting Network Firewall; all cross-service traffic routes through the inspection VPC.
  • Zero-downtime deployment uses ALB weighted target groups for blue/green traffic shifts: 10% canary for 10 minutes, then 50% for 10 minutes, then 100% cutover if error rate stays below 0.1%.
  • DNS TTL of 60 seconds on all failover-eligible records; DNS TTL of 3600 seconds on CloudFront distribution CNAME and static asset records.

Design Task 1 — Route 53 and Health Check Architecture

Design the Route 53 record set for api.ipl.srihayavadhana.in that routes viewers to the closest healthy region. Your design must handle three failure scenarios: a single AZ failure in Mumbai (should not trigger failover), all three AZs failing in Mumbai (should trigger failover within 90 seconds), and CloudFront origin group failover when the primary ALB returns 5xx (should trigger within 60 seconds of the ALB’s health check detecting failure).

Analogy🏏Cricket
🏏 Think of it like cricket: designing the Route 53 record set with calculated health checks is like a third-umpire protocol that reacts differently to a minor knock versus a genuine injury. Just as a single AZ failure in Mumbai must not trigger failover, one fielder tweaking a finger doesn't stop play — the side plays on. Just as all three AZs failing must trigger DNS failover within 90 seconds, a whole squad ruled unfit forces the match to move venues promptly. Just as CloudFront origin-group failover reroutes on 5xx within 60 seconds, the third umpire switches to the reserve camera the instant the main feed returns garbage, faster than a venue change. EvaluateTargetHealth and the calculated health check combine child probes the way an umpire weighs several signals before declaring a region truly out. The payoff: like officiating that ignores a scratch but acts fast on a real injury, this design fails over only for genuine regional loss, sparing needless disruption while guaranteeing prompt recovery.

Consider how EvaluateTargetHealth interacts with your calculated health check design. The ALB’s built-in target health evaluation runs every 30 seconds with a threshold of 2 unhealthy consecutive checks, meaning the ALB marks a target unhealthy after approximately 60 seconds. Your Route 53 health check runs every 30 seconds with a failure threshold of 3. Draw the timeline from a target failure event to the first DNS response that excludes the Mumbai record.

python
# Starter: Route 53 latency routing with calculated health checks.
# Complete the TODO sections as part of the exercise.
import boto3
r53 = boto3.client('route53')

# TODO 1: Create AZ-level health checks for Mumbai (ap-south-1).
# Each should check the ALB health check endpoint on port 443.
# Endpoint: https://ipl-alb-az{n}.ap-south-1.elb.amazonaws.com/health

# TODO 2: Create a calculated health check aggregating the three AZ checks.
# Threshold: 2 of 3 must pass for the region to be considered healthy.

# Reference: latency routing record with calculated health check.
r53.change_resource_record_sets(
    HostedZoneId='/hostedzone/IPLZONEID',
    ChangeBatch={'Changes': [{
        'Action': 'UPSERT',
        'ResourceRecordSet': {
            'Name': 'api.ipl.srihayavadhana.in', 'Type': 'A',
            'SetIdentifier': 'mumbai-latency',
            'Region': 'ap-south-1',
            'HealthCheckId': 'TODO_CALCULATED_HC_ID',
            'AliasTarget': {
                'HostedZoneId': 'ZP97RAFLXTNZK',
                'DNSName': 'ipl-scorecard-alb.ap-south-1.elb.amazonaws.com',
                'EvaluateTargetHealth': True,
            },
        },
    }]}
)
print('Latency record with health check configured.')

Design Task 2 — CloudFront Cache Behaviour Architecture

Design the CloudFront distribution with three cache behaviours for the three traffic profiles. For /api/scores/*, justify why CachingDisabled is correct even though it means every viewer request hits the origin: the answer lies in the 3-second update interval and the strong consistency requirement. For /api/players/*, calculate the cache hit rate improvement from a 60-second TTL given that player stats are queried by 8 million viewers for approximately 200 players, and each stat is updated at most once per over (every 6 deliveries, roughly every 2 minutes).

Analogy🏏Cricket
🏏 Think of it like cricket: designing three CloudFront cache behaviours is like deciding which scoreboard elements refresh every ball and which can hold for an over. Just as /api/scores/* uses CachingDisabled because scores update every 3 seconds and demand strong consistency, the live run total must repaint on every single delivery — a cached, stale figure would show the wrong score. Just as /api/players/* takes a 60-second TTL to lift the cache hit rate, a player's season-average panel can hold for a minute since it barely moves, sparing the statistician repeated lookups. Just as Lambda@Edge validates the JWT before the cache is checked, the gate steward verifies a fan's pass before they even reach the scoreboard, so no unauthenticated viewer is served. The payoff: like a scoreboard that repaints the volatile score instantly yet caches the steady stats, tuned cache behaviours keep live data fresh, cut origin load on slow-changing data, and block unauthorised requests at the edge.

Design the Lambda@Edge function placement for JWT validation. The validation function must execute before the cache is checked to prevent unauthenticated users from receiving cached responses intended for authenticated users. Map the function to the correct CloudFront trigger point and explain why attaching it to the origin request trigger instead would create a security vulnerability where cached responses from one authenticated user could be served to an unauthenticated user on a subsequent cache hit for the same URL.

python
# Starter: CloudFront distribution skeleton.
# Complete the CacheBehaviors and FunctionAssociations sections.
import boto3
cf = boto3.client('cloudfront')

dist_config = {
    'Comment': 'IPL Scorecard Platform — Multi-Region',
    'DefaultCacheBehavior': {
        'TargetOriginId': 'ipl-api-origin-group',  # origin group with Mumbai + Singapore
        'ViewerProtocolPolicy': 'redirect-to-https',
        'CachePolicyId': '4135ea2d-6df8-44a3-9df3-4b5a84be39ad',  # CachingDisabled
        # TODO: Add Lambda@Edge JWT validation at the correct trigger.
    },
    'CacheBehaviors': {
        'Quantity': 2,
        'Items': [
            # TODO: /api/players/* with 60-second TTL.
            # TODO: /static/* with 86400-second TTL and Compress=True.
        ],
    },
    'Origins': {'Quantity': 1, 'Items': [
        # TODO: Configure origin group with Mumbai ALB as primary and Singapore ALB as failover.
    ]},
    'Enabled': True,
    'PriceClass': 'PriceClass_All',
}
print('Distribution config skeleton ready — complete the TODOs.')

Design Task 3 — Blue/Green Deployment Runbook

Design the ALB weighted target group runbook for zero-downtime deployment of the scores microservice. The runbook must specify the exact sequence of API calls to shift traffic, the CloudWatch metrics to monitor at each stage, the error rate threshold that triggers an automatic rollback, and the minimum observation window at each traffic percentage before advancing to the next stage. The runbook should be executable by an on-call engineer under time pressure without referencing external documentation.

Analogy🏏Cricket
🏏 Think of it like cricket: writing the ALB weighted-target-group runbook is like a captain's exact plan for easing a new bowler into a tense chase over by over. Just as the runbook specifies the precise sequence of API calls to shift traffic, the plan names the exact order — one over at 10% of the workload, then a longer spell, then the full quota — with no improvising. Just as it lists the CloudWatch metrics to watch at each stage, the captain names the signals to track each over: run rate conceded, dot balls, and edges. Just as an error-rate threshold triggers automatic rollback, the plan pulls the newcomer the instant they breach an agreed economy rate, restoring the trusted bowler. Just as each traffic percentage needs a minimum observation window before advancing, the youngster must complete a full over cleanly before earning the next. The payoff: like a scripted plan that promotes a bowler only on proven overs and retreats instantly on trouble, the runbook shifts traffic to new code safely with metric-gated stages and a one-command rollback.
python
# Starter: Blue/green deployment runbook as executable code.
# Fill in the monitoring and rollback logic.
import boto3, time
elb = boto3.client('elbv2', region_name='ap-south-1')
cw  = boto3.client('cloudwatch', region_name='ap-south-1')

BLUE_TG  = 'arn:aws:elasticloadbalancing:ap-south-1:111:targetgroup/ipl-scores-blue/abc'
GREEN_TG = 'arn:aws:elasticloadbalancing:ap-south-1:111:targetgroup/ipl-scores-green/def'
LISTENER = 'arn:aws:elasticloadbalancing:ap-south-1:111:listener/app/ipl-alb/xyz/uvw'

def shift_traffic(blue_weight: int, green_weight: int):
    elb.modify_listener(
        ListenerArn=LISTENER,
        DefaultActions=[{'Type':'forward','ForwardConfig':{'TargetGroups':[
            {'TargetGroupArn': BLUE_TG,  'Weight': blue_weight},
            {'TargetGroupArn': GREEN_TG, 'Weight': green_weight},
        ]}}]
    )
    print(f'Traffic: blue={blue_weight}% green={green_weight}%')

def get_error_rate(tg_arn: str, minutes: int = 5) -> float:
    # TODO: Query CloudWatch HTTPCode_Target_5XX_Count and RequestCount
    # for the target group over the last {minutes} minutes.
    # Return error rate as a float between 0 and 1.
    pass

# TODO: Implement the deployment stages:
# Stage 1: 90/10 for 10 minutes; rollback if error rate > 0.001
# Stage 2: 50/50 for 10 minutes; rollback if error rate > 0.001
# Stage 3: 0/100 full cutover
print('Runbook skeleton ready — implement the staged rollout logic.')

Evaluation Criteria

  • Route 53 design includes latency routing records in both regions, calculated health checks with 2-of-3 AZ threshold, and EvaluateTargetHealth=True on all Alias records pointing to ALBs.
  • CloudFront distribution has three distinct cache behaviours with correct TTLs per traffic profile and Lambda@Edge JWT validation attached at the viewer-request trigger, not the origin-request trigger.
  • The blue/green runbook specifies exact CloudWatch metrics, numeric error rate thresholds, and minimum observation windows at each traffic percentage stage, making it executable without interpretation.
  • The architecture satisfies the Reliability pillar by achieving an RTO under 90 seconds for a full regional failure with no manual operator intervention required.
  • The Well-Architected review of the design identifies at least three potential HRIs across the Security, Reliability, and Cost Optimization pillars, with a proposed remediation for each.
  • The design explicitly addresses the JWT validation vulnerability: Lambda@Edge is attached at viewer-request, not origin-request, with a written explanation of the cache poisoning risk if attached at the wrong trigger.

Warning: A common error in this exercise is attaching the JWT validation Lambda@Edge function at the origin-request trigger rather than the viewer-request trigger. At origin-request, the function only executes on cache misses. This means an authenticated user’s response is cached by CloudFront, and a subsequent unauthenticated request for the same URL returns the cached response without triggering the JWT validation function, bypassing authentication entirely. Always attach authentication and authorisation functions at the viewer-request trigger.

Lesson 6 of 40
0% complete