Choose L4 vs L7 and LB placement, pick algorithms that react to real load, configure health checks, outlier ejection, draining and slow start, handle long-lived connections, and monitor load balance quality
A load balancer distributes incoming connections or requests across a pool of backend instances so that no instance is overloaded, failed instances are avoided, and capacity can be added or removed transparently. Load balancing happens at the edge (internet-facing LBs), inside the platform (internal LBs, ingress) and increasingly in clients themselves (service mesh sidecars, gRPC client-side balancing).
Figure 1 — Load balancing tiers — ShopNow
Figure 2 — L4 vs L7 load balancing
Vocabulary
Meaning
Target / upstream
Backend instance receiving traffic
Outlier ejection
Temporarily removing a misbehaving target
Draining
Letting in-flight requests finish before removal
Slow start
Gradually ramping traffic to new targets
Table 1 — Terms
2Why It Exists
Without good balancing
Consequence
Round robin with one slow pod
p99 dominated by that pod
No draining
Deploys drop in-flight requests
No slow start
Cold JVMs overwhelmed after scale-out
Sticky sessions
Uneven load, painful scale-in
Table 2 — Why
3Core Concepts — Algorithms
Figure 3 — Load-balancing algorithms
Algorithm
ShopNow use
Least outstanding requests
ALB for web/API tiers
Power of two choices + EWMA
Envoy/mesh between services
Consistent hash (ring hash)
Routing to cache nodes by key
Round robin
NLB flows (L4)
Table 3 — Algorithm per tier
Figure 4 — p99 latency with one slow pod
4How It Works Internally — L7 Balancing
Step
Detail
Accept TLS connection
Terminate TLS (ACM certificate)
Parse HTTP request
Host, path, headers
Match listener rule
/api/orders → orders target group
Choose target
Algorithm over healthy targets
Reuse backend connection
Keep-alive / HTTP/2 pool
Record outcome
Passive health, metrics
Table 4 — Per-request path
4ADeep Dive — Health Checking
Type
Detail
Active
LB polls /health/ready every 5–10 s
Passive
Observe real traffic errors/latency
Outlier ejection (Envoy)
5 consecutive 5xx → eject 30 s, max 20% ejected
Readiness vs liveness
LB uses readiness; don't route before warm-up
Fail-open
If all targets unhealthy, ALB routes to all (avoid total blackout)
Table 5 — Keep sick targets out
4BDeep Dive — Connection Management
Feature
Purpose
Keep-alive / HTTP/2
Avoid TCP+TLS setup per request
Deregistration delay
Draining 30–60 s on scale-in/deploy
Slow start
Ramp new targets over 60 s (JIT warm-up)
Idle timeouts
Align LB < backend keep-alive to avoid 502s
Max connections per target
Protect backends
Table 6 — Lifecycle
4CDeep Dive — Zones and Cross-Zone Balancing
Setting
Trade-off
Cross-zone on (ALB default)
Even load; cross-AZ data transfer
Zone-aware routing (mesh)
Lower latency and cost; imbalance risk if zones uneven
Zonal shift
Move traffic away from impaired AZ quickly
Guidance
Keep equal capacity per AZ; prefer local zone with fallback
Table 7 — Topology awareness
4DDeep Dive — Long-Lived Connections
Problem
Solution
gRPC/HTTP2 pins one connection to one pod
Client-side balancing (xDS) or L7 per-request LB
WebSockets never rebalance
Max connection age; reconnect with jitter
New pods get no traffic
Connection churn policies
Scale-in drops sockets
Graceful close with reconnect hints
Table 8 — Balance requests, not just connections
4EDeep Dive — LB Limits and Failure Modes
Issue
Mitigation
LB capacity ramp (sudden 10× spike)
Pre-warming requests/LCU reservation, NLB for extreme
# Spring Boot 4: graceful shutdown + readiness so draining works with the LBserver: shutdown: gracefulspring: lifecycle: timeout-per-shutdown-phase: 25smanagement: endpoint: health: probes: { enabled: true } group: readiness: { include: readinessState, db, redis }
6Practical Examples
6.1 Slow pod dominating p99
One order pod on a noisy node served requests in 800 ms. Round robin gave it 1/40 of traffic and p99 of 820 ms; least outstanding requests plus outlier ejection brought p99 to 150 ms.
6.2 Deploy errors
Each rolling deploy produced ~300 502s. Aligning deregistration delay (30 s), graceful shutdown (25 s) and readiness=false on SIGTERM eliminated them.
6.3 PayGrid gRPC imbalance
gRPC clients pinned HTTP/2 connections to a few pods after scale-out. Istio per-request balancing and max connection age of 5 min fixed the skew.
6.4 Worked example — idle timeouts
Layer
Timeout
ALB idle
60 s
Tomcat keep-alive
75 s (> ALB)
Table 10 — Avoid 502s
6.5 Worked example — slow start
Setting
Effect
60 s ramp
New pods warm JIT gently
Table 11 — Cold start
6.6 Worked example — max ejection
Setting
Reason
20%
Never eject most of the pool
Table 12 — Safety
6.7 Worked example — interview whiteboard
Prompt
Answer outline
"How does load balancing work and which algorithm would you use?"
"L4 (connections, huge throughput, static IPs) vs L7 (requests, routing, TLS). Placement: edge LB, ingress, client-side/mesh. Algorithms: round robin fails with uneven pods; least outstanding / P2C / EWMA follow real load; consistent hash for affinity. Health: readiness checks + passive outlier ejection with max %. Lifecycle: keep-alive, draining, slow start, aligned idle timeouts. Zone-aware with equal AZ capacity. Long-lived connections need per-request or client-side balancing. Monitor per-target load and errors."
Table 13 — Structured answer
6.8 Worked example — NovaBank internal
Choice
Reason
Internal NLB → Envoy
mTLS end to end
Table 14 — Security + balancing
6.9 Worked example — anti-patterns
Anti-pattern
Effect
Sticky sessions for convenience
Uneven load
Liveness as LB health
Routing to not-ready pods
Unlimited retries at LB
Amplification
Cross-zone off with uneven AZs
Hot zone
Table 15 — Common mistakes
6.10 Worked example — consistent hash
Use
Detail
Route by cartId to cache pods
Cache affinity
Table 16 — Affinity without stickiness
6.11 Worked example — weighted targets
Instance type
Weight
c7g.2xlarge
2
c7g.xlarge
1
Table 17 — Heterogeneous fleet
6.12 Worked example — zonal shift
Event
Action
AZ-b degraded
ARC zonal shift away 1 h
Table 18 — AZ incidents
6.13 Worked example — NLB for extreme load
Case
Reason
Sale-day 1M connections
NLB scales instantly
Table 19 — Capacity
6.14 Worked example — TLS
Pattern
Detail
Terminate at ALB, re-encrypt to pods
Compliance
Table 20 — Encryption
6.15 Worked example — WebSockets
Setting
Value
Max connection age
30 min + jitter
Table 21 — Rebalancing
6.16 Worked example — interview follow-ups
Follow-up
Answer
"Why not round robin?"
Ignores real load; slow pods hurt p99
"What is P2C?"
Pick two random targets, choose less loaded
Table 22 — Common probes
6.17 Worked example — checklist
Item
✔
L4/L7 choice
✔
Load-aware algorithm
✔
Readiness + ejection
✔
Draining + slow start
✔
Timeouts aligned
✔
Per-target metrics
✔
Table 23 — LB baseline
6.18 Worked example — metrics
Metric
Alert
Max/mean requests per target > 1.5
Imbalance
Table 24 — Observability
6.19 Worked example — retries
Setting
Value
Mesh retry on 503 once, budget 10%
Bounded
Table 25 — Resilience
6.20 Worked example — client-side LB
Tool
Use
Spring Cloud LoadBalancer / gRPC xDS
No central LB hop
Table 26 — Fewer hops
6.21 Worked example — interview scenario
Question
Answer
"New pods get no traffic after scale-out"
Long-lived connections — per-request LB, connection age
Table 27 — Diagnose
6.22 Worked example — GWLB
Use
Detail
Inline firewall appliances
Transparent insertion
Table 28 — Security appliances
6.23 Worked example — health path
Path
Content
/actuator/health/readiness
App + critical deps
Table 29 — Readiness design
6.24 Worked example — LB capacity
Metric
Watch
ALB LCUs
Pre-warm before sale
Table 30 — Limits
6.25 Worked example — cost
Choice
Impact
Zone-aware routing
−40% cross-AZ transfer
Table 31 — Economics
6.26 Worked example — documentation
Service
Algorithm
Health
orders
LOR
readiness, 10 s
Table 32 — Clarity
7Common Problems & Mistakes
Mistake
Fix
Round robin everywhere
Load-aware
No draining
Graceful shutdown
Sticky sessions
Stateless
Connection pinning
Per-request LB
Table 33 — Mistakes and fixes
The classic mistakes are defaults left unexamined. Round robin is used everywhere even though pods differ in speed, so one slow instance sets the whole service's tail latency. Liveness endpoints are wired as load balancer health checks, so pods receive traffic before they are ready, or stay in rotation when a critical dependency fails. Sticky sessions are added for convenience and then make load uneven and scale-in painful, when moving session state to Redis would make the tier stateless. Long-lived gRPC and WebSocket connections pin traffic to old pods after scaling. And retries configured at the balancer, the mesh and the client multiply into a retry storm, turning a partial failure into a full outage.
8Performance & Production Considerations
Consideration
Practice
Imbalance ratio
Monitor
5xx by target
Eject
Deploy error rate
Zero goal
Table 34 — Operating LBs
Operate the balancer as a production system in its own right. Dashboards should show requests and errors per target, not just totals, so an imbalance ratio above about 1.5, or one target with high 5xx, is visible immediately. Rolling deploys should produce zero errors; any non-zero count usually means draining, graceful shutdown and readiness are misaligned. Managed balancers scale gradually, so pre-warm or reserve capacity before a sale-day spike, or use NLB for sudden extreme load. Watch cross-zone data transfer too: zone-aware routing cut ShopNow's cross-AZ cost by about 40 percent, but it only works with equal capacity per zone. Rehearse zonal shift so traffic can leave an impaired zone within minutes.
9Architecture & Design Considerations
Guideline
Detail
Balance on real load
LOR, P2C
Eject fast, ramp slow
Outliers, slow start
Right layer
L4 edge, L7 routing
Table 35 — Design guidance
10Interview Questions & Answers
Q1BasicConcept
What does a load balancer do?
A load balancer spreads incoming connections or requests across a pool of backend instances, so no single instance is overloaded and the pool behaves like one reliable service. It also hides failures, by health-checking targets and routing only to those that are ready; enables scaling, because instances can be added or removed without clients noticing; and makes deployments safe through connection draining and slow start. Load balancing happens at several layers: internet-facing balancers such as AWS ALB or NLB, ingress controllers and internal balancers inside the platform, and client-side balancing in gRPC clients or service mesh sidecars. The choice of algorithm and health policy matters as much as having a balancer at all.
Q2BasicTrade-off
L4 vs L7?
L4 load balancing works on connections: it sees IP addresses and ports, forwards TCP or UDP flows, and picks a target once per connection. It is extremely fast, handles millions of connections, can preserve client IPs and offers static addresses, which is why AWS NLB suits extreme or non-HTTP traffic. L7 load balancing understands the application protocol: it terminates TLS, reads hosts, paths and headers, routes each request by rules, can retry, and can balance individual HTTP/2 or gRPC requests over shared connections. The cost is more processing per request. A common pattern combines both: an NLB at the edge for raw capacity, then an L7 ingress or mesh for routing.
Q3IntermediateTricky
Why is round robin risky?
Round robin assumes every target is equal and every request costs the same, and neither is true in production. If one pod sits on a noisy node or is stuck in long GC pauses, it still receives its full share of requests, which queue up behind it. At ShopNow, one pod answering in 800 ms received a fortieth of the traffic and pushed p99 to 820 ms for the whole service. Round robin also ignores mixed instance sizes and the difference between heavy and light requests. Load-aware algorithms such as least outstanding requests, power of two choices or latency-based EWMA send less traffic to slow targets automatically; with outlier ejection, p99 fell to 150 ms.
Q4IntermediateInternals
What is connection draining?
Connection draining, called deregistration delay on AWS, means the load balancer stops sending new requests to a target that is being removed but lets in-flight requests finish before the target is fully dropped. It matters during scale-in and on every rolling deploy. To work end to end, the application must cooperate: on SIGTERM it should fail its readiness check, keep serving existing requests and shut down gracefully within a timeout shorter than the drain period. In the ShopNow example, aligning a 30-second deregistration delay with Spring Boot graceful shutdown at 25 seconds and readiness set to false on SIGTERM eliminated about 300 errors with status 502 per deploy.
Q5Senior EngineerInternals
What is outlier ejection?
Outlier ejection is passive health checking: the load balancer or sidecar watches real traffic and temporarily removes a target that is misbehaving, even if its health endpoint still reports healthy. In Envoy or Istio you might eject a host after five consecutive 5xx responses, keep it out for 30 seconds and lengthen the ejection for repeat offenders. It catches problems that active checks miss, such as a pod with a broken downstream connection or a degraded node. The critical safety setting is the maximum ejection percentage, for example 20 percent, so a shared problem such as a failing database cannot make the balancer eject the entire pool and turn degradation into an outage.
Q6Senior EngineerInternals
What is power of two choices?
Power of two choices picks two targets at random and sends the request to the less loaded of the two, measured by outstanding requests or a latency estimate. It sounds trivial, but it gives load distribution close to always choosing the least-loaded target, without the cost and herd behaviour of finding the global minimum. When many independent balancers, such as sidecars, all pick the single least-loaded host from slightly stale data, they stampede it at the same moment; random sampling prevents that. Envoy's LEAST_REQUEST policy uses it by default, and combining it with EWMA latency makes it react quickly to an instance that has become slow.
Q7Technical ArchitectScenario
How handle gRPC connection pinning?
gRPC runs over long-lived HTTP/2 connections, and an L4 balancer picks a target only when a connection opens. After scale-out, existing clients keep their connections to the old pods, so new pods get almost no traffic while old ones stay hot. The fix is to balance per request, not per connection. Use an L7 proxy or service mesh that spreads individual gRPC streams across backends, or client-side balancing with xDS or a headless service so each client holds connections to many pods. Set a maximum connection age, such as five minutes with jitter, so connections are recycled, and send GOAWAY on scale-in so clients reconnect cleanly elsewhere.
Q8Technical ArchitectTricky
Why align idle timeouts?
Because if the backend closes an idle keep-alive connection before the load balancer does, the balancer may send a new request on a connection that is already closing, and the client receives a 502. It appears as a small, steady trickle of errors that is hard to reproduce. The rule is that each hop's idle timeout must be longer than that of the hop in front of it. With an ALB idle timeout of 60 seconds, the Tomcat or Netty keep-alive timeout should be longer, for example 75 seconds. The same rule applies through every proxy layer, including service meshes, NAT gateways and client connection pools.
Q9Solution ArchitectTrade-off
When use consistent hashing?
When requests benefit from always reaching the same backend for a given key, usually because that backend holds state or a warm cache for it. Routing by cartId or userId to cache nodes, sharded in-memory stores or stateful stream processors keeps hit rates high and avoids duplicate work. Consistent hashing, such as ring hash or Maglev, means adding or removing a node remaps only about one nth of the keys instead of reshuffling everything. The trade-off is balance: hot keys create hot nodes, and the algorithm ignores current load. Mitigate with virtual nodes and bounded-load consistent hashing, and keep it away from stateless tiers, where least-request balancing is better.
Q10Solution ArchitectDesign
What LB metrics matter?
Per-target metrics matter more than aggregate ones, because averages hide the single bad instance. I watch load imbalance, such as the ratio of maximum to mean requests or in-flight requests per target, alerting above about 1.5; 5xx rate and latency percentiles broken down by target and by zone; ejection counts and healthy host counts; and connection metrics such as active connections, new connection rate and rejections. At the balancer itself, track capacity units such as ALB LCUs before big events, TLS errors, and target response time against total time. Deploy-time 5xx is a key signal as well: the goal is zero errors during rolling deployments.
Newsletter
Get new tutorials every week
New ArchitectMind tutorials and interview questions, once a week. No spam, unsubscribe anytime.
Your subscription could not be saved. Please try again.
Almost done! Check your inbox and click the confirmation link to complete your subscription.