Cloud Load Balancing: Picking the Right Balancer Type on GCP
The single most common mistake teams make with GCP load balancing, in practice, isn’t a misconfiguration — it’s picking the wrong load balancer type before configuration even starts. GCP offers a genuinely wide menu (global vs regional, external vs internal, HTTP(S) vs TCP/UDP vs SSL proxy), and unlike some clouds where “load balancer” is close to a single product with a few options, GCP’s offerings solve meaningfully different problems. Picking based on “which one has the features I’ve heard of” instead of “what traffic pattern do I actually have” is how teams end up fighting their load balancer instead of it doing its job invisibly.
This is a decision-tree problem more than a feature-comparison problem, so that’s the lens worth using.
The Decision Tree
Most teams building a standard public web application land on the Global External Application Load Balancer — it’s the right default for HTTP(S) traffic from users anywhere, and it’s the one that integrates with Cloud CDN and Cloud Armor. The other types exist for genuinely different traffic shapes: raw TCP/UDP protocols that aren’t HTTP, internal service-to-service traffic that should never touch the public internet, and cases where preserving the original client IP at the network layer matters more than HTTP-aware routing.
Global Application Load Balancer: How It Actually Works
User (anywhere in the world) │ ▼Google's edge network (nearest point of presence) │ ▼Global forwarding rule (single anycast IP) │ ▼URL map (routes by path/host) │ ┌────┴────┬─────────────┐ ▼ ▼ ▼Backend Backend Backendservice A service B service C(us-central1) (europe-west1) (asia-east1)The anycast IP is the feature that makes this genuinely different from a traditional load balancer — one single IP address is announced from every Google point of presence globally, and a user’s traffic automatically routes to the nearest edge location and then to the closest healthy backend, without any DNS-based geo-routing tricks or per-region load balancer coordination. This is a real architectural advantage: a global application with backends in multiple regions gets automatic latency-based routing and cross-region failover essentially for free, as a property of the load balancer rather than something you build.
Setting Up a Global Application Load Balancer
# Create a health checkgcloud compute health-checks create http my-health-check \ --port=80 \ --request-path=/healthz
# Create a backend service and attach an instance groupgcloud compute backend-services create my-backend-service \ --global \ --health-checks=my-health-check \ --protocol=HTTP
gcloud compute backend-services add-backend my-backend-service \ --global \ --instance-group=my-instance-group \ --instance-group-zone=us-central1-a
# Create a URL map, target proxy, and global forwarding rulegcloud compute url-maps create my-url-map \ --default-service=my-backend-service
gcloud compute target-http-proxies create my-http-proxy \ --url-map=my-url-map
gcloud compute forwarding-rules create my-forwarding-rule \ --global \ --target-http-proxy=my-http-proxy \ --ports=80Each of these pieces has a distinct job: the health check determines which backend instances are actually eligible to receive traffic, the backend service groups instances and defines balancing behavior, the URL map handles path/host-based routing decisions, and the forwarding rule is what actually binds a public IP to the whole chain. Understanding this layered structure is what makes debugging tractable later — “traffic isn’t reaching my service” almost always traces back to one specific layer in this chain, and knowing the chain means knowing where to look first.
Path-Based and Host-Based Routing
A single global load balancer can route different paths or hostnames to entirely different backend services — genuinely useful for consolidating what would otherwise be several separate load balancers:
gcloud compute url-maps add-path-matcher my-url-map \ --path-matcher-name=api-matcher \ --default-service=web-backend \ --path-rules="/api/*=api-backend,/static/*=static-backend"Requests to /api/orders route to the API backend, /static/logo.png routes to a static-asset backend (possibly a Cloud Storage bucket serving directly), and everything else falls through to the default web backend — one IP, one certificate, one load balancer managing what functionally behaves like several independent services underneath.
Health Checks: The Mechanism That Actually Prevents Outages
Load balancing without health checks is just traffic distribution — health checks are what turn it into actual availability protection, by continuously probing backend instances and routing traffic only to ones currently passing.
gcloud compute health-checks create http my-health-check \ --port=80 \ --request-path=/healthz \ --check-interval=10s \ --timeout=5s \ --healthy-threshold=2 \ --unhealthy-threshold=3The threshold values matter more than they might seem — unhealthy-threshold=3 means an instance needs three consecutive failed checks before being pulled from rotation, which avoids flapping a healthy-but-briefly-slow instance in and out of service on a single transient blip, while still reacting within roughly 30 seconds (three checks at a 10-second interval) to a genuine failure. Tuning these values too aggressively (removing instances after one failed check) or too conservatively (requiring ten consecutive failures) are both real failure modes worth avoiding deliberately rather than accepting defaults blindly.
The Full Load Balancer Menu, Compared
Beyond the decision tree’s main branches, it’s worth having the complete picture in one place, since GCP’s console lists these by name without much context on when each actually applies.
┌─────────────────────────┬───────┬──────────┬──────────────────────────┐│ Type │ Layer │ Scope │ Best for │├─────────────────────────┼───────┼──────────┼──────────────────────────┤│ Global External App LB │ 7 │ Global │ Public HTTP(S), multi-region││ Regional External App LB │ 7 │ Regional │ Public HTTP(S), single region││ Internal Application LB │ 7 │ Regional │ Internal microservice routing││ External Passthrough NLB │ 4 │ Regional │ Raw TCP/UDP, preserve source IP││ Internal Passthrough NLB │ 4 │ Regional │ Internal TCP/UDP, low latency││ SSL Proxy LB │ 4 (TLS)│ Global │ Non-HTTP TLS traffic (e.g. custom protocols)││ TCP Proxy LB │ 4 │ Global │ Non-HTTP TCP needing global anycast│└─────────────────────────┴───────┴──────────┴──────────────────────────┘The passthrough network load balancer deserves a specific callout: “passthrough” means it doesn’t terminate the connection the way an Application or Proxy load balancer does — packets are forwarded with the original source IP intact, and the backend instance sees the real client IP directly. This matters for protocols or compliance requirements where knowing the true originating IP at the application layer is a hard requirement, not just a nice-to-have — something a proxy-based load balancer (which replaces the source IP with its own by design) can’t provide without additional header-based workarounds.
Real-World Use Case: Global SaaS Application
A SaaS product with customers across North America, Europe, and Asia is the textbook case for the global load balancer’s value. Rather than running separate regional deployments with manual DNS-based routing and independent certificate management for each region, one global load balancer with backends in three regions gives every user automatic routing to their nearest healthy backend, one managed SSL certificate covering the whole setup, and automatic failover if an entire region becomes unhealthy — a user in Europe transparently starts being served from the US region if the European backend fails, without any DNS TTL delay or manual intervention.
Best Practices
- Match the load balancer type to the actual traffic pattern, not to feature familiarity — a regional balancer is genuinely the right choice for regional-only traffic, and reaching for global by default adds complexity without benefit.
- Tune health check thresholds deliberately based on your application’s actual startup and failure characteristics, not generic defaults.
- Use path/host-based routing to consolidate load balancers where it genuinely simplifies architecture, but don’t force unrelated services behind one balancer just to save on IP addresses — operational clarity matters more than resource count.
- Enable logging on backend services from the start — load balancer request logs are frequently the fastest way to diagnose a routing or backend issue, and they’re not retroactive.
Common Mistakes
Choosing global when regional (or vice versa) actually fits better. A purely regional application gains nothing from global load balancing except cost and complexity; a genuinely global application under-served by a regional balancer loses the automatic latency-routing and failover that’s the whole point of going global.
Under-tuning health check sensitivity for the application’s real startup time. An application with a slow cold start getting marked unhealthy and cycled out of rotation before it’s actually ready is a self-inflicted availability problem, not a load balancer bug.
Forgetting that backend service settings (timeout, session affinity) need to match the application’s actual behavior. A long-running request type with a default 30-second backend timeout gets silently cut off — this is a common source of intermittent, hard-to-reproduce errors that trace back to a load balancer setting, not application code.
Frequently Asked Questions
What’s the difference between an Application Load Balancer and a Network Load Balancer? Application (Layer 7) load balancers understand HTTP — they can route by path, host, and headers, and terminate TLS. Network (Layer 4) load balancers operate on raw TCP/UDP without understanding the protocol content, which is necessary for non-HTTP traffic and scenarios needing the original client IP preserved at the connection level.
Can I use Cloud Load Balancing with on-premises backends? Yes, via hybrid connectivity (Cloud VPN or Interconnect) combined with a hybrid network endpoint group, letting a GCP load balancer route to backends outside GCP — useful during a gradual migration.
Does the global load balancer’s single IP address change if I add or remove backend regions? No — the anycast IP remains stable regardless of backend topology changes, which is one of its practical advantages for DNS and client configuration stability.
Is there a cost difference between global and regional load balancers? Yes, pricing structures differ, and global load balancers generally carry a different (often higher for equivalent traffic) cost structure than regional ones — worth factoring into the type decision alongside the architectural fit, not as an afterthought.
What does “passthrough” actually mean for a network load balancer, practically? It means the backend instance’s operating system sees the real client IP and port directly on the connection, rather than a proxy’s own IP — necessary for applications that need genuine client IP visibility at the network layer, such as certain licensing systems or protocols that embed IP-based logic.
Can one load balancer serve both HTTP and raw TCP traffic? Not directly through the same forwarding rule — HTTP(S) traffic needs an Application Load Balancer’s Layer 7 awareness, while non-HTTP TCP/UDP needs a Network or Proxy load balancer. Mixed-protocol applications typically run two load balancer configurations, one per traffic type, often sharing the same backend VPC.
A Final Note on Naming Consistency
One small but genuinely useful habit worth adopting: name backend services, health checks, and forwarding rules consistently enough that their relationship is obvious from the name alone — checkout-backend, checkout-health-check, checkout-forwarding-rule rather than a mix of naming conventions accumulated over time by different engineers. This sounds trivial until you’re six months into an incident-response scramble trying to figure out which of fifteen similarly-named resources actually belongs to the service that’s down, and a consistent naming convention turns that lookup into something obvious at a glance instead of a several-minute detour in the middle of troubleshooting something urgent.
Summary
Getting GCP load balancing right starts with correctly identifying the actual traffic pattern — global HTTP(S) traffic, regional-only traffic, raw TCP/UDP, or internal service mesh traffic — rather than defaulting to whichever type sounds most capable. The global Application Load Balancer’s anycast IP and automatic latency-based routing are genuinely powerful for the right use case and unnecessary complexity for the wrong one. Once the type is chosen correctly, the remaining work — health check tuning, routing rules, backend service configuration — is where most of the actual operational reliability gets built or lost, quietly, long after the initial setup is forgotten by whoever configured it first and moved on to other work.