Skip to content
ProfessionalProLoad Balancing

Lab 26: Two Load Balancers, One Empty Zone, One Set Of 503s

An Application Load Balancer and a Network Load Balancer in the same two zones, pointed at the same single healthy target, both with cross-zone off. The Network Load Balancer serves every request. The Application Load Balancer fails about half of them with 503, and the half it fails is decided by DNS before the request is sent.

Debugging time
~30 min
Reading time
10 min
Reported by
Application Platform
Tier
Professional
INC-1891SEV-2InvestigatingOpened 2026-10-01 09:20 UTC

ALB returning 503 on roughly half of requests; only target is healthy; NLB on the same instance is fine

Reported by Application Platform

We moved the service behind an Application Load Balancer last night. Since then about half of all requests get a 503 from the load balancer itself, not from us: the application never sees them and our access log has nothing for them. The other half are fine.

The target group has one instance and it is healthy. It has been healthy the whole time. Health check is HTTP on /, matcher 200, and the instance answers 200.

Here is the part I cannot explain. The network team fronts the same instance with a Network Load Balancer for a different consumer, same two subnets, same instance, same port, and it has not failed once. Same target, two load balancers, one of them broken.

What you are working with

One VPC, two Availability Zones, two load balancers, one target.

Starting state — both load balancers span two zones, the target lives in one
VPC lab 10.26.0.0/16 AZ a contains subnet-a 10.26.1.0/24, holding ALB node a, NLB node a, App. AZ b contains subnet-b 10.26.2.0/24, holding ALB node b, NLB node b, Control host.VPC lab 10.26.0.0/16AZ asubnet-apublic10.26.1.0/24ALB node ahas a targetNLB node ahas a targetApp10.26.1.50, healthyAZ bsubnet-bpublic10.26.2.0/24ALB node bno target, in DNSNLB node bno target, not inDNSControl hostthe client

Each load balancer has a node in each enabled zone and, with cross-zone off, each node may only send to targets in its own zone. Zone b has none. The two load balancers agree on that fact and disagree about what to do with it: the Application Load Balancer leaves its zone-b address in DNS, the Network Load Balancer withdraws its own. The client in zone b is about to find out which one it resolved.

ResourceConfiguration
ALBInternal, subnets a and b
ALB target groupHTTP:80, one target in zone a, cross-zone false
NLBInternal, subnets a and b, cross-zone off (default)
NLB target groupTCP:80, same target, HTTP health check
App10.26.1.50, zone a, Python HTTP server, healthy in both groups
Control hostzone b, the client
  1. EC2

    Control host

    resolves the ALB name

  2. RTB

    DNS

    two addresses, one per zone

  3. GW

    ALB node, zone b

    cross-zone off; permitted targets: those in zone b

    Dropped — The node is in DNS and accepts the connection, then looks for a target in its own zone. There is none. The load balancer answers 503 itself. The target never sees the request.

  4. DEST

    App, zone a

    healthy, idle

The request is refused one hop after DNS, by a node that was published as reachable. Nothing on the target side participates.

Scope and constraints

  • In scope: why two load balancers with identical topology and an identical healthy target produce different results, and what DNS has to do with it.
  • Out of scope: the application, the health check, security groups, subnets, the Network Load Balancer. All correct.
  • The reporter is right that the target is healthy and right that the NLB is fine. Both facts are evidence, not noise.
  • The fix is one target group attribute, or one more instance. The lab does the attribute.

Deploy the broken state

cd lab-26-alb-empty-zone-503
terraform init
terraform apply

About four minutes for both load balancers to become active and the target to pass its initial health checks. Confirm before testing:

aws elbv2 describe-target-health --target-group-arn "$(terraform output -raw alb_target_group_arn)" \
  --query 'TargetHealthDescriptions[].TargetHealth.State' --output text
# healthy
aws elbv2 describe-target-health --target-group-arn "$(terraform output -raw nlb_target_group_arn)" \
  --query 'TargetHealthDescriptions[].TargetHealth.State' --output text
# healthy