Loadbalancing und Caching mit NginX

Datum

Verwendete Version: Nginx 1.13.1

NginX hat in den letzten Jahren interessante Features bekommen, darunter zählt vor allem das Loadbalancing (gleichmäßiges Verteilen der Anfragen auf mehre Backends) und Caching (Zwischenspeichern von Elementen).

Loadbalancing

Nginx bietet die Möglichkeit ankommenden Anfragen nach verschiedenen Möglichkeiten an entsprechende Backends zu senden.
Hierbei beherrscht Nginx auch Health-Checks, welche prüfen ob ein Backend erreichbar ist oder nicht.
Die entsprechenden Optionen für die Feinjustierung findet man hier: http://nginx.org/en/docs .

Auf dem System, welches als Loadbalancer fungieren soll, legt man in der NginX-Konfigurationsdatei die Liste mit den Backends an:

http {
    upstream techgoat-balance {
        server 192.168.2.30;
        server 192.168.2.31;
        server 192.168.2.32;
   }

Nun gibt man noch die Location an:

server {
        listen 80;
        location / {
            proxy_pass http://techgoat-balance;
        }
    }

Das Ganze funktioniert natürlich auch mit https anstatt http.

Anpassung des Loadbalancing

Werden keine weiteren Optionen angegeben, so geschieht das Balancing per round-robin.
Nginx bietet folgende Möglichkeiten:

round-robin

Alle Anfragen werden gleichmäßig auf alle vorhandenen Backends aufgeteilt.

Beispielkonfiguration:

http {
    upstream techgoat-balance {
        server 192.168.2.30;
        server 192.168.2.31;
        server 192.168.2.32;
   }
least-connected

Die nächsten Anfragen werden auf das Backend mit den wenigsten Verbindungen gesendet.
Hierbei versucht Nginx einen ausgelasteten App-Server nicht weiter mit Anfragen zu belästigen sondern verteilt die Anfragen an andere Backends.

Beispielkonfiguration:

http {
    upstream techgoat-balance {
        least_conn;
        server 192.168.2.30;
        server 192.168.2.31;
        server 192.168.2.32;
   }
Session persistence

Bei den obrigen Konfigurationen kann es passieren, dass jede neue Anfrage auf einem anderem Backend landet. Das ist nicht praktikabel wenn man mit Sessions arbeitet. Darum gibt es die Option ip_hash, diese erstellt von jeder IP einen Hash um dann zu entscheiden auf welches Backend die Anfrage gesendet wird. Dies stellt sicher, dass der gleiche Client auch immer auf dem gleichen Backend landet.

Beispielkonfiguration:

http {
    upstream techgoat-balance {
        ip_hash;
        server 192.168.2.30;
        server 192.168.2.31;
        server 192.168.2.32;
   }
Gewichtung

Es lässt sich auch statisch festlegen, welche Backends stärker belastet werden sollen.

Beispielkonfiguration:

http {
    upstream techgoat-balance {
        server 192.168.2.30 weight=3;
        server 192.168.2.31;
        server 192.168.2.32;
   }

Bei dieser Gewichtung teilen sich die nächsten 5 Anfragen folgendermaßen auf:
192.168.2.30 bekommt 3 Anfragen
192.168.2.31 bekommt 1 Anfrage
192.168.2.32 bekommt 1 Anfrage

Caching

Sofern möglich, sollten Elemente wie z.B. Bilder (gif, jpg, png, etc..) oder Stylesheets (css) gecacht werden und nicht bei jeder Anfrage neu vom Backend geladen werden, da sich solche Dateien sehr selten ändern.
Dazu trägt man auf dem Backend-Server im server -Block der Nginx-Konfigurationsdatei die Elemente ein, welche zwischengespeichert werden soll und wie lange:

location ~* \.(?:css|js|gif|png|jpg)$ {
                 expires 168h;
                 access_log off;
                add_header Cache-Control "public";
	}

Hierbei werden nun alle css, js, gif, png, jpg Dateien 1Woche lang zwischengespeichert.

$ curl -IX GET http://192.168.2.54/test.png
HTTP/1.1 200 OK
Server: nginx/1.13.1
Date: Mon, 05 Feb 2018 14:54:45 GMT
Content-Type: image/png
Content-Length: 42200
Connection: keep-alive
Last-Modified: Mon, 04 Nov 2013 07:07:12 GMT
ETag: "527747a0-a4d8"
Expires: Mon, 12 Feb 2018 14:54:45 GMT
Cache-Control: max-age=604800
Cache-Control: public
Accept-Ranges: bytes

Um zu testen ob das Caching funktioniert, kann man sich das Ergebnis im Header der Anfrage sehen, dazu fügt man auf dem Loadbalancer-System folgende Elemente in die Nginx-Konfigurationsdatei ein:

proxy_cache_path /tmp/nginx levels=1:2 keys_zone=meine_zone:10m;
server {
...
    location / {
          ...
         add_header X-Proxy-Cache $upstream_cache_status;
         proxy_cache meine_zone;
         ...
        }
}

proxy_cache_path gibt den Pfad an wo du zwischengespeicherten Dateien abgelegt werden.
levels gibt dabei an wie die Dateien auf dem System zwischengespeichert werden (bei 1:2 werden die Dateien in entsprechenden Unterverzeichnissen abgelegt, basierend auf Ihrem md5-Hash.
keys_zone gibt den Namen der Zone an und es wird ein Limit von 10 MB festgesetzt.

Nun sollte ein weiterer Header dazu gekommen sein:

$ curl -ILX GET http://192.168.2.54/test.png
HTTP/1.1 200 OK
Server: nginx/1.13.1
Date: Mon, 05 Feb 2018 15:02:15 GMT
...
Cache-Control: max-age=604800
Cache-Control: public
X-Proxy-Cache: MISS
Accept-Ranges: bytes

Ein nochmaliger nochmaliger Aufruf sollte einen HIT zeigen…

$ curl -ILX GET http://192.168.2.54/test.png
HTTP/1.1 200 OK
Server: nginx/1.13.1
Date: Mon, 05 Feb 2018 15:02:26 GMT
...
Cache-Control: max-age=604800
Cache-Control: public
X-Proxy-Cache: HIT
Accept-Ranges: bytes

Autor
Kategorien Software, Server

PRTG Map