Questions
Design a global load balancing architecture with Cloud CDN for a multi-region application.
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.
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.
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
| Feature | Global HTTP(S) | Regional | Network LB |
|---|---|---|---|
| Scope | Global | Regional | Regional |
| Protocol | HTTP/HTTPS | HTTP/HTTPS | TCP/UDP |
| CDN | Yes | No | No |
| Anycast | Yes | No | No |
| SSL termination | Yes | Yes | No |
| Use case | Web apps | Internal | Low-level |
Failover Behavior
| Scenario | Behavior | Recovery Time |
|---|---|---|
| Instance unhealthy | Routes to healthy instances | ~10 seconds |
| Zone failure | Routes to other zones | ~10 seconds |
| Region failure | Routes to other regions | ~10 seconds |
| All backends unhealthy | Returns 502 | Manual intervention |
Practice Question
Why does Google Cloud's Global HTTP(S) Load Balancer use a single anycast IP address instead of regional IP addresses?