01 · Definition
What is load balancing?
Load balancing is distributing incoming requests across a pool of servers (instances, containers or pods) so that each handles a fair share and the service keeps running when one of them fails. A load balancer sits in front of the pool at a single address. For a WhatsApp integration that address is usually your webhook callback URL and your internal send API: Meta POSTs every inbound message and status to one HTTPS URL, and the load balancer decides which webhook receiver handles each request.
Two choices define a load balancer. The algorithm picks who gets the next request: round-robin takes turns, weighted round-robin favours bigger instances, least-connections picks the instance with the fewest open requests, and hash-based routing (consistent hashing) sends the same key, such as a wa_id or a tenant, to the same instance. The Health Check decides who is eligible at all: the balancer probes each instance, or counts its failed responses, stops sending traffic to one that fails, and adds it back once it recovers.
Load balancers also work at different layers. A layer 4 (TCP) balancer forwards connections without reading them. A layer 7 (HTTP) balancer terminates TLS, reads paths and headers, and can route /webhooks/whatsapp and /api/sends to different pools. Load balancing spreads traffic over the capacity you already have; Horizontal Scaling adds capacity to the pool, and together they are the basis of High Availability, with Failover covering the switch to a standby when a whole tier fails.
Key takeaways
- Load balancing spreads requests across a pool of instances behind one address, so no instance is overloaded and failures are routed around.
- The algorithm decides who gets the next request; the health check decides who is eligible at all.
- Least-connections is a sound default for webhook receivers, whose requests vary in cost.
- The balancer must pass the raw body unchanged, or
X-Hub-Signature-256verification fails. - Load balancing spreads traffic over existing capacity; horizontal scaling adds the capacity.
02 · Specifications
Load balancing: key facts and limits
| Common algorithms | Round-robin, weighted, least-connections, consistent hash |
|---|---|
| Layer 4 vs layer 7 | TCP forwarding vs HTTP-aware routing with TLS termination |
| Health check types | Active probes and passive failure counting |
| Webhook payload size | Up to 3 MB: raise body-size limits |
| Signature check | Raw body must reach the app unchanged |
| Meta on failed webhooks | Retries with decreasing frequency for up to 7 days |
03 · Operation
How does load balancing work?
Put one address in front of the pool
Register the load balancer's HTTPS URL as the webhook callback URL. TLS, with a valid CA-signed certificate, terminates at the balancer or passes through to the instances.
Choose an algorithm
Least-connections suits webhook receivers, whose requests vary in cost. Round-robin is fine when every request is cheap and the instances are identical. Consistent hashing on a key keeps related work on one instance.
Configure health checks
Probe a readiness endpoint every few seconds and remove an instance after a few consecutive failures. Readiness should reflect the instance itself, such as whether it can reach its queue, not whether Meta's API is slow.
Drain before removing
On deploys and scale-in, stop sending new requests to an instance but let in-flight ones finish (connection draining), so no webhook is cut off half-way and retried.
Pass the request through intact
Forward the raw body unchanged so
X-Hub-Signature-256still verifies, pass the client address inX-Forwarded-For, and raise body-size limits: WhatsApp webhook payloads can reach 3 MB.
04 · Code samples
Load balancing in code
# /etc/nginx/conf.d/whatsapp-webhooks.confupstream webhook_receivers {least_conn; # fewest active requests winsserver 10.0.1.11:3000 max_fails=3 fail_timeout=10s;server 10.0.1.12:3000 max_fails=3 fail_timeout=10s;server 10.0.1.13:3000 max_fails=3 fail_timeout=10s;keepalive 32;}server {listen 443 ssl;server_name hooks.example.in;ssl_certificate /etc/ssl/hooks.example.in.pem;ssl_certificate_key /etc/ssl/hooks.example.in.key;client_max_body_size 4m; # webhook payloads can reach 3 MBlocation /webhooks/whatsapp {proxy_pass http://webhook_receivers;proxy_http_version 1.1;proxy_set_header Connection "";proxy_set_header Host $host;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_read_timeout 10s;# Once a POST has reached an upstream, NGINX does not replay it on# another server (unless non_idempotent is added). Keep it that way:# your handler, not the balancer, owns retries.proxy_next_upstream error timeout;}}
Open-source NGINX marks a server failed passively (max_fails within fail_timeout); cloud balancers and orchestrators probe a readiness endpoint actively.
05Playground
A working model of Load Balancing. Use its controls to replay it step by step.
Route ten webhooks: which instance takes each one?
Gives each chat to whoever has the fewest open conversations right now.
Incoming · 0 left
- All 10 conversations have been routed.
Conversation 10 of 10 · Least busy
wa 64018 · status deliveredgoes toMedia 3
Least busy: Media 3 has the fewest open chats (3 of 4).
- Full
Web 1
3 of 3 open
- Generalist
- wa 77310 · inbound text
- wa 77310 · status delivered
- wa 90233 · inbound documentneeds media(skill mismatch)
- Full
Web 2
3 of 3 open
- Generalist
- wa 98201 · status read
- wa 64018 · inbound text
- wa 98201 · inbound reply
- Full
Media 3
4 of 4 open
- media
- wa 98201 · status delivered
- wa 55102 · inbound imageneeds media
- wa 55102 · status read
- wa 64018 · status delivered
Waiting · 0
- Nobody waiting: every conversation found an agent.
| Strategy | Routed | Waiting | Skill mismatches |
|---|---|---|---|
| Least busy | 10 | 0 | 1 |
| Round-robin | 10 | 0 | 2 |
| Sticky | 10 | 0 | 2 |
| Skills-based | 10 | 0 | 0 |
Conversation 10 of 10, wa 64018 · status delivered: Least busy: Media 3 has the fewest open chats (3 of 4).
06 · Cautions
Common mistakes with load balancing
Health checks that call Meta
If readiness depends on the Graph API, one slow Meta response marks every instance unhealthy at once and the balancer has nowhere to send traffic. Check only what the instance itself controls.
Retrying POSTs at the balancer
Letting the balancer replay a webhook or send request on another instance after a timeout can process it twice. Keep retries of non-idempotent requests off at the balancer and handle them in code.
Sticky sessions as a crutch
Pinning users to instances hides state that belongs in a shared store, and unbalances the pool when one big tenant is busy. Keep receivers stateless and use hashing only where ordering truly needs it.
Default body limits and timeouts
Many proxies cap bodies at 1 MB and close idle connections after 60 seconds. Raise the limit for 3 MB webhook payloads, and align timeouts across balancer, app and client.
Killing instances without draining
Removing an instance mid-request cuts webhooks off and triggers Meta retries and duplicates. Fail readiness first, wait for in-flight requests to finish, then stop.
07 · Rationale
Why does load balancing matter?
Meta delivers webhook traffic in bursts: a broadcast to 50,000 customers produces a wave of sent, delivered and read statuses within minutes, and Meta retries any request that does not get a timely 200. A single receiver is both a bottleneck and a single point of failure, so one crash or deploy and statuses start backing up. A load balancer with honest health checks keeps the endpoint answering through deploys, crashes and spikes. That is what keeps your Webhook Acknowledgement fast and your delivery data fresh.
08 · Worked example: One receiver fails during a renewal campaign
Example: One receiver fails during a renewal campaign
A Chennai insurance broker runs three webhook receivers behind a layer 7 load balancer using least-connections. During a renewal-reminder broadcast, status webhooks climb from 20 to 600 requests a second. One receiver loses its queue connection; its readiness probe fails twice in ten seconds, and the balancer stops routing to it while the other two absorb the traffic. Meta sees nothing but fast 200 responses. The failed instance reconnects, passes its probe and rejoins the pool, with no events lost and no retry storm.
09 · Recommended practice
Best practices for load balancing
- Run at least three instances across two availability zones, so one failure still leaves headroom.
- Alert on the number of healthy instances, not only on error rates.
- Log the instance ID with every request so a bad node is easy to spot.
- Load-test through the balancer, not around it: its limits are part of your capacity.
10 · Questions and answers
Load Balancing FAQs
- Do I need a load balancer for a WhatsApp webhook?
- Not on day one, but yes once uptime matters. A single receiver is a single point of failure; two or more instances behind a balancer keep webhooks answering through crashes, deploys and broadcast spikes.
- What is the difference between load balancing and horizontal scaling?
- Horizontal scaling adds instances; load balancing spreads requests across them. You need both: extra instances are useless if traffic cannot reach them, and a balancer cannot rescue a pool that is too small.
- Which load-balancing algorithm should I use for webhooks?
- Least-connections is a sound default for webhook receivers. Their requests vary in cost (media, batched statuses), so sending each one to the least busy instance evens out load better than strict round-robin.
- Will a load balancer break X-Hub-Signature-256 verification?
- Not if it passes the body through unchanged. Signature checks fail when a proxy re-encodes, decompresses or rewrites the body; plain HTTP proxying that keeps the raw bytes verifies normally.