DeployU
Interviews / Cloud & DevOps / Design a global load balancing architecture with Cloud CDN for a multi-region application.

Design a global load balancing architecture with Cloud CDN for a multi-region application.

architecture Load Balancing Interactive Quiz Code Examples

The Scenario

Your application serves users globally and needs:

  • Low latency for users worldwide (< 100ms)
  • High availability (99.99% uptime target)
  • Automatic failover between regions
  • Static content cached at edge locations
  • SSL termination with managed certificates

Current setup: Single region deployment with 300ms latency for users in Asia and Europe.

The Challenge

Design a multi-region architecture using Global HTTP(S) Load Balancer, Cloud CDN, and backend services in multiple regions. Explain the traffic flow and failover behavior.

Wrong Approach

A junior engineer might deploy separate load balancers in each region (requiring users to know which endpoint to use), skip Cloud CDN for dynamic content, use self-managed SSL certificates, or implement DNS-based failover (slow). These approaches increase complexity, don't leverage GCP's global network, and have slower failover.

Right Approach

A senior engineer uses a single Global HTTP(S) Load Balancer with a global anycast IP, backend services with instance groups in multiple regions, Cloud CDN for static and cacheable content, and Google-managed SSL certificates. Traffic automatically routes to the nearest healthy region.

Architecture Overview

                         Users Worldwide


                    ┌─────────────────────┐
                    │   Global Anycast IP  │
                    │    (Single IP)       │
                    └──────────┬──────────┘

                    ┌──────────▼──────────┐
                    │  Global HTTP(S) LB   │
                    │  + Cloud CDN         │
                    │  + Cloud Armor       │
                    └──────────┬──────────┘

          ┌────────────────────┼────────────────────┐
          │                    │                    │
          ▼                    ▼                    ▼
    ┌───────────┐        ┌───────────┐        ┌───────────┐
    │us-central1│        │ europe-   │        │  asia-    │
    │ Backend   │        │  west1    │        │  east1    │
    │ Service   │        │  Backend  │        │  Backend  │
    └─────┬─────┘        └─────┬─────┘        └─────┬─────┘
          │                    │                    │
          ▼                    ▼                    ▼
    ┌───────────┐        ┌───────────┐        ┌───────────┐
    │ GKE / GCE │        │ GKE / GCE │        │ GKE / GCE │
    │  + Cloud  │        │  + Cloud  │        │  + Cloud  │
    │   SQL     │        │   SQL     │        │   SQL     │
    └───────────┘        └───────────┘        └───────────┘

Step 1: Create Backend Services in Multiple Regions

# Instance group in us-central1
resource "google_compute_instance_group_manager" "us" {
  name               = "app-mig-us"
  base_instance_name = "app"
  zone               = "us-central1-a"

  version {
    instance_template = google_compute_instance_template.app.id
  }

  target_size = 3

  named_port {
    name = "http"
    port = 8080
  }

  auto_healing_policies {
    health_check      = google_compute_health_check.app.id
    initial_delay_sec = 300
  }
}

# Instance group in europe-west1
resource "google_compute_instance_group_manager" "eu" {
  name               = "app-mig-eu"
  base_instance_name = "app"
  zone               = "europe-west1-b"

  version {
    instance_template = google_compute_instance_template.app.id
  }

  target_size = 3

  named_port {
    name = "http"
    port = 8080
  }
}

# Instance group in asia-east1
resource "google_compute_instance_group_manager" "asia" {
  name               = "app-mig-asia"
  base_instance_name = "app"
  zone               = "asia-east1-a"

  version {
    instance_template = google_compute_instance_template.app.id
  }

  target_size = 3

  named_port {
    name = "http"
    port = 8080
  }
}

Step 2: Configure Health Checks

resource "google_compute_health_check" "app" {
  name               = "app-health-check"
  check_interval_sec = 5
  timeout_sec        = 5
  healthy_threshold  = 2
  unhealthy_threshold = 3

  http_health_check {
    port         = 8080
    request_path = "/health"
  }

  log_config {
    enable = true
  }
}

Step 3: Create Backend Service with Multiple Backends

resource "google_compute_backend_service" "app" {
  name                  = "app-backend"
  protocol              = "HTTP"
  port_name             = "http"
  timeout_sec           = 30
  health_checks         = [google_compute_health_check.app.id]
  load_balancing_scheme = "EXTERNAL_MANAGED"

  # Enable Cloud CDN
  enable_cdn = true

  cdn_policy {
    cache_mode = "CACHE_ALL_STATIC"
    default_ttl = 3600
    max_ttl     = 86400

    cache_key_policy {
      include_host         = true
      include_protocol     = true
      include_query_string = false
    }
  }

  # Connection draining for graceful shutdown
  connection_draining_timeout_sec = 300

  # Logging
  log_config {
    enable      = true
    sample_rate = 1.0
  }

  # US backend (primary for US users)
  backend {
    group           = google_compute_instance_group_manager.us.instance_group
    balancing_mode  = "UTILIZATION"
    capacity_scaler = 1.0
    max_utilization = 0.8
  }

  # EU backend
  backend {
    group           = google_compute_instance_group_manager.eu.instance_group
    balancing_mode  = "UTILIZATION"
    capacity_scaler = 1.0
    max_utilization = 0.8
  }

  # Asia backend
  backend {
    group           = google_compute_instance_group_manager.asia.instance_group
    balancing_mode  = "UTILIZATION"
    capacity_scaler = 1.0
    max_utilization = 0.8
  }
}

Step 4: Configure URL Map and SSL

# URL Map for routing
resource "google_compute_url_map" "app" {
  name            = "app-url-map"
  default_service = google_compute_backend_service.app.id

  host_rule {
    hosts        = ["app.example.com"]
    path_matcher = "app"
  }

  path_matcher {
    name            = "app"
    default_service = google_compute_backend_service.app.id

    # Route static content to CDN-optimized backend
    path_rule {
      paths   = ["/static/*", "/images/*", "/css/*", "/js/*"]
      service = google_compute_backend_service.static.id
    }

    # Route API calls to backend service
    path_rule {
      paths   = ["/api/*"]
      service = google_compute_backend_service.api.id
    }
  }
}

# Google-managed SSL certificate
resource "google_compute_managed_ssl_certificate" "app" {
  name = "app-ssl-cert"

  managed {
    domains = ["app.example.com", "www.example.com"]
  }
}

# HTTPS proxy
resource "google_compute_target_https_proxy" "app" {
  name             = "app-https-proxy"
  url_map          = google_compute_url_map.app.id
  ssl_certificates = [google_compute_managed_ssl_certificate.app.id]

  ssl_policy = google_compute_ssl_policy.modern.id
}

# SSL policy (modern TLS only)
resource "google_compute_ssl_policy" "modern" {
  name            = "modern-ssl-policy"
  profile         = "MODERN"
  min_tls_version = "TLS_1_2"
}

# Global forwarding rule
resource "google_compute_global_forwarding_rule" "https" {
  name                  = "app-https-forwarding"
  target                = google_compute_target_https_proxy.app.id
  port_range            = "443"
  ip_address            = google_compute_global_address.app.address
  load_balancing_scheme = "EXTERNAL_MANAGED"
}

# Static global IP
resource "google_compute_global_address" "app" {
  name = "app-global-ip"
}

Step 5: Add Cloud Armor for Security

resource "google_compute_security_policy" "app" {
  name = "app-security-policy"

  # Default rule - allow
  rule {
    action   = "allow"
    priority = "2147483647"
    match {
      versioned_expr = "SRC_IPS_V1"
      config {
        src_ip_ranges = ["*"]
      }
    }
    description = "Default allow rule"
  }

  # Block known bad IPs
  rule {
    action   = "deny(403)"
    priority = "1000"
    match {
      versioned_expr = "SRC_IPS_V1"
      config {
        src_ip_ranges = ["192.0.2.0/24"]  # Example blocked range
      }
    }
    description = "Block malicious IPs"
  }

  # Rate limiting
  rule {
    action   = "rate_based_ban"
    priority = "2000"
    match {
      versioned_expr = "SRC_IPS_V1"
      config {
        src_ip_ranges = ["*"]
      }
    }
    rate_limit_options {
      conform_action = "allow"
      exceed_action  = "deny(429)"
      rate_limit_threshold {
        count        = 1000
        interval_sec = 60
      }
      ban_duration_sec = 600
    }
    description = "Rate limit - 1000 req/min per IP"
  }

  # OWASP ModSecurity rules
  rule {
    action   = "deny(403)"
    priority = "3000"
    match {
      expr {
        expression = "evaluatePreconfiguredExpr('sqli-v33-stable')"
      }
    }
    description = "SQL injection protection"
  }
}

# Attach security policy to backend
resource "google_compute_backend_service" "app" {
  # ... other config ...
  security_policy = google_compute_security_policy.app.id
}

Step 6: Configure DNS

resource "google_dns_record_set" "app" {
  name         = "app.example.com."
  managed_zone = google_dns_managed_zone.example.name
  type         = "A"
  ttl          = 300
  rrdatas      = [google_compute_global_address.app.address]
}

Traffic Flow

1. User in Tokyo requests app.example.com
2. DNS resolves to global anycast IP
3. Request enters Google's network at Tokyo edge
4. Global LB routes to asia-east1 backend (closest)
5. If Asia region unhealthy, routes to US or EU
6. Static content served from CDN cache
7. Response returns via same path

Load Balancing Comparison

FeatureGlobal HTTP(S)RegionalNetwork LB
ScopeGlobalRegionalRegional
ProtocolHTTP/HTTPSHTTP/HTTPSTCP/UDP
CDNYesNoNo
AnycastYesNoNo
SSL terminationYesYesNo
Use caseWeb appsInternalLow-level

Failover Behavior

ScenarioBehaviorRecovery Time
Instance unhealthyRoutes to healthy instances~10 seconds
Zone failureRoutes to other zones~10 seconds
Region failureRoutes to other regions~10 seconds
All backends unhealthyReturns 502Manual intervention

Practice Question

Why does Google Cloud's Global HTTP(S) Load Balancer use a single anycast IP address instead of regional IP addresses?