Praktische gids voor load balancing met nginx

Veel ontwikkelaars gebruiken nginx alleen als "reverse proxy + statische bestandsserver", maar nginx is in feite een krachtige software load balancer. Als je zelf servers beheert, kun je met een goede nginx-configuratie de stabiliteit en prestaties van je service aanzienlijk verbeteren.

In dit artikel richten we ons op beginners tot gevorderden en behandelen we:

  • Het concept van load balancing
  • Hoe je nginx configureert voor load balancing
  • Verschillende algoritmen (round robin, least_conn, ip_hash, etc.)
  • Gezondheidschecks (health checks)
  • Veelgebruikte opties

1. Wat is load balancing?



Load balancing is simpel gezegd:

"Verdeel verzoeken gelijkmatig over meerdere servers zodat geen enkele server overbelast raakt."

Waarom is het nodig?

  1. Bescherming tegen verkeerspieken * Zorgt dat een server niet crasht bij een plotselinge toename van verzoeken.
  2. Schaalbaarheid (scale-out) * In plaats van een enkele server te upgraden, kun je meerdere servers horizontaal toevoegen.
  3. Fouttolerantie (high availability) * Als één server uitvalt, blijft de service door verkeer naar andere servers te sturen.

Waar staat nginx in?

De typische architectuur ziet er zo uit:

Client → nginx (load balancer / reverse proxy) → meerdere applicatieservers

Hier ontvangt nginx het verzoek en stuurt het door naar één van de achterliggende applicatieservers.


2. Basisstructuur van nginx load balancing

In de nginx-configuratie draait load balancing om twee hoofdonderdelen:

  1. upstream-blok * Definieert de "backend server pool".
  2. server / location-blok * Bepaalt welke upstream gebruikt moet worden voor inkomende verzoeken.

Hieronder een eenvoudig voorbeeld.

http {
    upstream app_backend {
        server 10.0.0.101:3000;
        server 10.0.0.102:3000;
    }

    server {
        listen 80;
        server_name example.com;

        location / {
            proxy_pass http://app_backend;

            # Standaard proxy headers
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

Wat betekent deze configuratie?

  • upstream app_backend bundelt twee applicatieservers in één pool.
  • proxy_pass http://app_backend; stuurt het verzoek naar één server in de pool.
  • Als je geen algoritme specificeert, is de standaard round robin.

3. Soorten load balancing algoritmen



nginx biedt verschillende distributiestrategieën. Kies de juiste voor je situatie.

3.1 Basis: round robin

Standaard als je niets specificeert.

upstream app_backend {
    server 10.0.0.101:3000;
    server 10.0.0.102:3000;
}
  • Eerste verzoek → Server 1
  • Tweede verzoek → Server 2
  • Derde verzoek → weer Server 1 …

Voordelen: eenvoudig en werkt in de meeste gevallen. Nadelen: houdt geen rekening met huidige belasting.


3.2 least_conn (minimale actieve verbindingen)

upstream app_backend {
    least_conn;
    server 10.0.0.101:3000;
    server 10.0.0.102:3000;
}

Verzendt nieuwe verzoeken naar de server met de minste actieve verbindingen.

Aanbevolen scenario: * Sommige verzoeken duren lang, andere zijn kort. * Servers hebben vergelijkbare specificaties, maar verzoekpatronen zijn ongelijk.


3.3 ip_hash (zelfde client → dezelfde server)

upstream app_backend {
    ip_hash;
    server 10.0.0.101:3000;
    server 10.0.0.102:3000;
}

Hash van het client-IP zorgt ervoor dat dezelfde client altijd naar dezelfde server gaat.

Voordelen: eenvoudig voor sticky sessions. Nadelen: bij toevoegen of verwijderen van servers kunnen veel mappings veranderen; werkt niet als het echte client-IP verborgen is (bijv. Cloudflare, ELB).


3.4 Gewicht (weight) gebaseerd

upstream app_backend {
    server 10.0.0.101:3000 weight=3;
    server 10.0.0.102:3000 weight=1;
}

Verdeel verzoeken in een 3:1 verhouding. Handig als servers verschillende specificaties hebben.


4. Health checks en foutafhandeling

Een slimme load balancer moet automatisch uitgevallen servers verwijderen. nginx open-source ondersteunt passieve health checks.

4.1 max_fails / fail_timeout

upstream app_backend {
    server 10.0.0.101:3000 max_fails=3 fail_timeout=30s;
    server 10.0.0.102:3000 max_fails=3 fail_timeout=30s;
}
  • max_fails=3 → na drie opeenvolgende fouten wordt de server als niet-werkend beschouwd.
  • fail_timeout=30s → gedurende 30 seconden wordt er geen verkeer naar die server gestuurd.

Fouten omvatten meestal 502/503/504 of verbindingsfouten.


4.2 proxy_next_upstream

Bepaalt wanneer het verzoek naar de volgende server wordt doorgestuurd.

location / {
    proxy_pass http://app_backend;
    proxy_next_upstream error timeout http_502 http_503 http_504;
}

Verhoogt de betrouwbaarheid, maar overmatig herhalen kan vertragingen veroorzaken.


5. Praktijkvoorbeeld: eenvoudige webservice load balancing

Stel je hebt twee Node.js-applicatieservers op poort 3000:

  • 10.0.0.101:3000
  • 10.0.0.102:3000

5.1 nginx-configuratie

http {
    upstream app_backend {
        least_conn;

        server 10.0.0.101:3000 max_fails=3 fail_timeout=30s;
        server 10.0.0.102:3000 max_fails=3 fail_timeout=30s;
    }

    server {
        listen 80;
        server_name myservice.com;

        location / {
            proxy_pass http://app_backend;

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_read_timeout 60s;
            proxy_connect_timeout 5s;
            proxy_send_timeout 10s;
        }
    }
}

Na het herladen van nginx:

  • Alle verzoeken aan myservice.com worden naar de minder belastte Node.js-server gestuurd.
  • Een server die meerdere opeenvolgende fouten geeft, wordt tijdelijk uitgesloten.

6. HTTPS (SSL) terminatie + load balancing

In productie wordt bijna altijd HTTPS gebruikt. Het meest gangbare patroon is nginx als SSL-terminator.

http {
    upstream app_backend {
        least_conn;
        server 10.0.0.101:3000;
        server 10.0.0.102:3000;
    }

    server {
        listen 443 ssl;
        server_name myservice.com;

        ssl_certificate     /etc/letsencrypt/live/myservice.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/myservice.com/privkey.pem;

        location / {
            proxy_pass http://app_backend;

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }

    # HTTP → HTTPS redirect
    server {
        listen 80;
        server_name myservice.com;
        return 301 https://$host$request_uri;
    }
}
  • Client ↔ nginx: HTTPS
  • nginx ↔ backend: HTTP (intern netwerk)

7. Sticky sessions: zijn ze echt nodig?

Vroeger werden sessies vaak in het geheugen van de server opgeslagen, waardoor dezelfde gebruiker naar dezelfde server moest gaan.

Met ip_hash kun je dit eenvoudig oplossen, maar tegenwoordig gebruiken we meestal:

  • Externe opslag (bijv. Redis) voor sessies
  • JWT voor stateless authenticatie

Het is vaak beter om de applicatie stateless te maken en de load balancer puur voor verkeerverdeling te gebruiken.


8. Veelvoorkomende optimalisaties

8.1 keepalive

Hergebruik van backend-verbindingen verbetert de prestaties.

upstream app_backend {
    least_conn;
    server 10.0.0.101:3000;
    server 10.0.0.102:3000;

    keepalive 32;
}

server {
    location / {
        proxy_pass http://app_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}
  • keepalive 32; → maximaal 32 keepalive-verbindingen per worker.

8.2 buffers & timeouts

Voor grote antwoorden of trage backends zijn buffers en timeouts cruciaal.

location / {
    proxy_pass http://app_backend;

    proxy_buffering on;
    proxy_buffers 16 16k;
    proxy_busy_buffers_size 64k;

    proxy_read_timeout 60s;
    proxy_send_timeout 60s;
}

Pas aan op basis van je trafficpatroon en backend‑prestaties.


9. Implementatiestrategie (stapsgewijs)

Als je al een draaiende service hebt op één server, kun je als volgt opschalen:

  1. Stap 1: nginx als reverse proxy * Client → nginx → bestaande server * Gebruik SSL‑terminatie, caching, statische bestanden.
  2. Stap 2: servers dupliceren en upstream configureren * Voeg een tweede server toe aan de upstream.
  3. Stap 3: health checks & monitoring * Configureer max_fails, fail_timeout, proxy_next_upstream. * Implementeer log‑ en metriekverzameling (bijv. Prometheus + Grafana).
  4. Stap 4: algoritme & fine‑tuning * Kies least_conn of weight op basis van traffic. * Optimaliseer keepalive, buffers, timeouts.

Conclusie

nginx is veel meer dan een eenvoudige reverse proxy; het biedt een robuuste load balancing‑functionaliteit.

  • Definieer een upstream voor je serverpool.
  • Kies het juiste load balancing‑algoritme.
  • Implementeer health checks en herstelschema’s.
  • Combineer met HTTPS‑terminatie voor veiligheid en prestaties.

Met deze kennis kun je een stabilere en schaalbaardere infrastructuur opzetten, zelfs als je verkeer begint te groeien.

image