Grundlegendes zu Nginx HTTP-Proxying, Load Balancing, Buffering und Caching

Einführung

In diesem Handbuch werden die HTTP-Proxy-Funktionen von Nginx erläutert, mit denen Nginx Anforderungen zur weiteren Verarbeitung an Back-End-HTTP-Server weiterleiten kann. Nginx wird häufig als Reverse-Proxy-Lösung eingerichtet, um die Infrastruktur zu skalieren oder Anforderungen an andere Server weiterzuleiten, die nicht für die Verarbeitung großer Clientlasten ausgelegt sind.

Währenddessen werden wir diskutieren, wie Sie mithilfe der integrierten Lastausgleichsfunktionen von Nginx skalieren können. Wir werden auch das Puffern und Zwischenspeichern untersuchen, um die Leistung von Proxy-Operationen für Clients zu verbessern.

Allgemeine Proxy-Informationen

Wenn Sie in der Vergangenheit nur Webserver für einfache Einzelserverkonfigurationen verwendet haben, fragen Sie sich möglicherweise, warum Sie Proxy-Anforderungen benötigen.

Ein Grund für den Proxy von Nginx zu anderen Servern ist die Möglichkeit, Ihre Infrastruktur zu skalieren. Nginx ist für die gleichzeitige Verarbeitung vieler gleichzeitiger Verbindungen ausgelegt. Dies macht es ideal als Anlaufstelle für Kunden. Der Server kann Anforderungen an eine beliebige Anzahl von Back-End-Servern weiterleiten, um den Großteil der Arbeit zu erledigen, wodurch die Last auf Ihre Infrastruktur verteilt wird. Dieses Design bietet Ihnen auch die Flexibilität, Back-End-Server einfach hinzuzufügen oder bei Bedarf für Wartungszwecke herunterzufahren.

Ein anderer Fall, in dem ein HTTP-Proxy nützlich sein kann, ist die Verwendung von Anwendungsservern, die möglicherweise nicht für die direkte Verarbeitung von Anforderungen von Clients in Produktionsumgebungen erstellt wurden. Viele Frameworks enthalten Webserver, aber die meisten von ihnen sind nicht so robust wie Server, die für hohe Leistung ausgelegt sind, wie Nginx. Wenn Sie Nginx vor diese Server stellen, können Sie die Benutzererfahrung verbessern und die Sicherheit erhöhen.

Das Proxy-Verfahren in Nginx wird ausgeführt, indem eine an den Nginx-Server gerichtete Anforderung bearbeitet und zur eigentlichen Verarbeitung an andere Server weitergeleitet wird. Das Ergebnis der Anforderung wird an Nginx zurückgegeben, das die Informationen dann an den Client weiterleitet. Die anderen Server in dieser Instanz können Remotecomputer, lokale Server oder sogar andere in Nginx definierte virtuelle Server sein. Die Server, an die Nginx-Proxys Anforderungen stellen, werden alsupstream servers bezeichnet.

Nginx kann Proxy-Anforderungen an Server senden, die über die Protokolle http (s), FastCGI, SCGI und uwsgi oder memcached über separate Richtliniensätze für jeden Proxy-Typ kommunizieren. In diesem Handbuch konzentrieren wir uns auf das http-Protokoll. Die Nginx-Instanz ist dafür verantwortlich, die Anforderung weiterzuleiten und alle Nachrichtenkomponenten in einem Format zu massieren, das der Upstream-Server verstehen kann.

Dekonstruieren eines grundlegenden HTTP-Proxy-Passes

Der einfachste Proxy-Typ besteht darin, eine Anforderung an einen einzelnen Server weiterzuleiten, der über http kommunizieren kann. Diese Art von Proxy wird als generischer "Proxy-Pass" bezeichnet und von der treffend benanntenproxy_pass-Richtlinie behandelt.

Dieproxy_pass-Direktive findet sich hauptsächlich in Standortkontexten. Sie ist auch inif Blöcken innerhalb eines Standortkontexts und inlimit_except Kontexten gültig. Wenn eine Anforderung mit einem Speicherort übereinstimmt, in dem sich eineproxy_pass-Direktive befindet, wird die Anfrage an die von der Direktive angegebene URL weitergeleitet.

Schauen wir uns ein Beispiel an:

# server context

location /match/here {
    proxy_pass http://example.com;
}

. . .

Im obigen Konfigurations-Snippet wird am Ende des Servers in der Definition vonproxy_passkein URI angegeben. Für Definitionen, die diesem Muster entsprechen, wird der vom Client angeforderte URI unverändert an den Upstream-Server übergeben.

Wenn beispielsweise eine Anforderung für/match/here/please von diesem Block verarbeitet wird, wird der Anforderungs-URI alshttp://example.com/match/here/please an den Server vonexample.com gesendet.

Schauen wir uns das alternative Szenario an:

# server context

location /match/here {
    proxy_pass http://example.com/new/prefix;
}

. . .

Im obigen Beispiel wird der Proxyserver mit einem URI-Segment am Ende (/new/prefix) definiert. Wenn in der Definition vonproxy_passein URI angegeben ist, wird der Teil der Anforderung, der mit der Definition vonlocationübereinstimmt, während des Durchlaufs durch diesen URI ersetzt.

Beispielsweise wird eine Anforderung für/match/here/please auf dem Nginx-Server alshttp://example.com/new/prefix/please an den Upstream-Server übergeben. Die/match/here werden durch/new/prefix ersetzt. Dies ist ein wichtiger Punkt, den Sie berücksichtigen sollten.

Manchmal ist ein solcher Austausch unmöglich. In diesen Fällen wird der URI am Ende derproxy_pass-Definition ignoriert und entweder der ursprüngliche URI vom Client oder der von anderen Anweisungen geänderte URI an den Upstream-Server übergeben.

Wenn beispielsweise der Speicherort mit regulären Ausdrücken abgeglichen wird, kann Nginx nicht feststellen, welcher Teil des URI mit dem Ausdruck übereinstimmt, und sendet daher den ursprünglichen Client-Anforderungs-URI. Ein anderes Beispiel ist, wenn eine Rewrite-Direktive am selben Ort verwendet wird, wodurch der Client-URI umgeschrieben wird, aber immer noch im selben Block behandelt wird. In diesem Fall wird der umgeschriebene URI übergeben.

Verstehen, wie Nginx Header verarbeitet

Eine Sache, die möglicherweise nicht sofort klar ist, ist, dass es wichtig ist, mehr als nur den URI zu übergeben, wenn Sie erwarten, dass der Upstream-Server die Anforderung ordnungsgemäß verarbeitet. Die Anfrage, die von Nginx im Auftrag eines Kunden eingeht, sieht anders aus als eine Anfrage, die direkt von einem Kunden eingeht. Ein großer Teil davon sind die Header, die mit der Anfrage einhergehen.

Wenn Nginx eine Anfrage als Proxy fungiert, werden automatisch einige Anpassungen an den Anforderungsheadern vorgenommen, die es vom Client erhält:

  • Nginx entfernt alle leeren Header. Es hat keinen Sinn, leere Werte an einen anderen Server weiterzuleiten. es würde nur dazu dienen, die Bitte aufzublähen.

  • Standardmäßig betrachtet Nginx alle Header, die Unterstriche enthalten, als ungültig. Diese werden aus der Proxy-Anfrage entfernt. Wenn Sie möchten, dass Nginx diese als gültig interpretiert, können Sie die Direktiveunderscores_in_headersauf "on" setzen, da Ihre Header sonst niemals zum Backend-Server gelangen.

  • Der "Host" -Header wird auf den Wert umgeschrieben, der durch die Variable$proxy_hostdefiniert ist. Dies ist die IP-Adresse oder der Name und die Portnummer des Upstreams, direkt wie in der Direktiveproxy_passdefiniert.

  • Der Header "Connection" wird in "close" geändert. Dieser Header wird verwendet, um Informationen über die bestimmte Verbindung zu signalisieren, die zwischen zwei Parteien hergestellt wurde. In diesem Fall setzt Nginx dies auf "Schließen", um dem Upstream-Server anzuzeigen, dass diese Verbindung geschlossen wird, sobald auf die ursprüngliche Anforderung geantwortet wird. Der Upstream sollte nicht damit rechnen, dass diese Verbindung bestehen bleibt.

Der erste Punkt, den wir aus dem Obigen extrapolieren können, ist, dass jeder Header, den Siedo notübergeben möchten, auf eine leere Zeichenfolge gesetzt werden sollte. Header mit leeren Werten werden vollständig aus der übergebenen Anforderung entfernt.

Der nächste Punkt, der aus den obigen Informationen hervorgeht, ist, dass Sie sicherstellen müssen, dassdo not Unterstriche aufweisen, wenn Ihre Backend-Anwendung nicht standardmäßige Header verarbeitet. Wenn Sie Header benötigen, die einen Unterstrich verwenden, können Sie die Direktiveunderscores_in_headersweiter oben in Ihrer Konfiguration auf "Ein" setzen (gültig entweder im http-Kontext oder im Kontext der Standardserverdeklaration für die IP-Adresse / den IP-Port Kombination). Wenn Sie dies nicht tun, markiert Nginx diese Header als ungültig und legt sie stillschweigend ab, bevor sie an Ihren Upstream weitergeleitet werden.

Der "Host" -Header ist in den meisten Proxy-Szenarien von besonderer Bedeutung. Wie oben angegeben, wird dies standardmäßig auf den Wert$proxy_host gesetzt, eine Variable, die den Domänennamen oder die IP-Adresse und den Port enthält, die direkt aus der Definition vonproxy_passtammen. Dies ist standardmäßig ausgewählt, da dies die einzige Adresse ist, auf die Nginx sicher sein kann, dass der Upstream-Server antwortet (da sie direkt aus den Verbindungsinformationen abgerufen wird).

Die gebräuchlichsten Werte für den "Host" -Header sind nachstehend aufgeführt:

  • $proxy_host: Hiermit wird der "Host" -Header auf den Domänennamen oder die Kombination aus IP-Adresse und Port aus der Definition vonproxy_passgesetzt. Dies ist aus Sicht von Nginx die Standardeinstellung und "sicher", aber normalerweise nicht das, was der Proxy-Server benötigt, um die Anforderung korrekt zu verarbeiten.

  • $http_host: Setzt den "Host" -Header aus der Clientanforderung auf den "Host" -Header. Die vom Client gesendeten Header stehen in Nginx immer als Variablen zur Verfügung. Die Variablen beginnen mit dem Präfix$http_, gefolgt vom Headernamen in Kleinbuchstaben, wobei alle Bindestriche durch Unterstriche ersetzt werden. Obwohl die Variable$http_hostdie meiste Zeit funktioniert, kann dies dazu führen, dass der Pass fehlschlägt, wenn die Clientanforderung keinen gültigen "Host" -Header hat.

  • $host: Diese Variable wird in der Reihenfolge ihrer Präferenz festgelegt: der Hostname aus der Anforderungszeile selbst, der "Host" -Header aus der Clientanforderung oder der Servername, der der Anforderung entspricht.

In den meisten Fällen möchten Sie den Header „Host“ auf die Variable$hostetzen. Es ist am flexibelsten und stellt den Proxy-Servern in der Regel einen „Host“ -Header zur Verfügung, der so genau wie möglich ausgefüllt wird.

Header setzen oder zurücksetzen

Um Header für Proxy-Verbindungen anzupassen oder festzulegen, können Sie die Direktiveproxy_set_headerverwenden. Um beispielsweise den "Host" -Header wie beschrieben zu ändern und einige zusätzliche Header hinzuzufügen, die bei Proxy-Anforderungen häufig vorkommen, können Sie Folgendes verwenden:

# server context

location /match/here {
    proxy_set_header HOST $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    proxy_pass http://example.com/new/prefix;
}

. . .

Die obige Anforderung setzt den "Host" -Header auf die Variable$host, die Informationen über den ursprünglich angeforderten Host enthalten sollte. Der HeaderX-Forwarded-Protogibt dem Proxyserver Informationen über das Schema der ursprünglichen Clientanforderung (unabhängig davon, ob es sich um eine http- oder eine https-Anforderung handelt).

X-Real-IP wird auf die IP-Adresse des Clients gesetzt, damit der Proxy basierend auf diesen Informationen Entscheidungen richtig treffen oder protokollieren kann. DerX-Forwarded-For-Header ist eine Liste, die die IP-Adressen aller Server enthält, über die der Client bis zu diesem Zeitpunkt einen Proxy durchgeführt hat. Im obigen Beispiel setzen wir dies auf die Variable$proxy_add_x_forwarded_for. Diese Variable nimmt den Wert des ursprünglichenX-Forwarded-For-Headers, der vom Client abgerufen wurde, und fügt am Ende die IP-Adresse des Nginx-Servers hinzu.

Natürlich könnten wir die Direktiven vonproxy_set_headerin den Server- oder http-Kontext verschieben, sodass auf sie an mehr als einem Ort verwiesen werden kann:

# server context

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

location /match/here {
    proxy_pass http://example.com/new/prefix;
}

location /different/match {
    proxy_pass http://example.com;
}

Definieren eines Upstream-Kontexts zum Lastenausgleich für Proxy-Verbindungen

In den vorherigen Beispielen haben wir gezeigt, wie ein einfacher HTTP-Proxy für einen einzelnen Back-End-Server erstellt wird. Mit Nginx können wir diese Konfiguration einfach skalieren, indem wir ganze Pools von Back-End-Servern angeben, an die wir Anforderungen weiterleiten können.

Wir können dies tun, indem wir die Direktiveupstreamverwenden, um einen Pool von Servern zu definieren. Bei dieser Konfiguration wird davon ausgegangen, dass einer der aufgelisteten Server die Anforderungen eines Clients verarbeiten kann. Auf diese Weise können wir unsere Infrastruktur nahezu mühelos ausbauen. Die Direktiveupstreammuss im http-Kontext Ihrer Nginx-Konfiguration festgelegt werden.

Schauen wir uns ein einfaches Beispiel an:

# http context

upstream backend_hosts {
    server host1.example.com;
    server host2.example.com;
    server host3.example.com;
}

server {
    listen 80;
    server_name example.com;

    location /proxy-me {
        proxy_pass http://backend_hosts;
    }
}

Im obigen Beispiel haben wir einen Upstream-Kontext namensbackend_hosts eingerichtet. Nach der Definition steht dieser Name für die Verwendung in Proxy-Pässen zur Verfügung, als ob es sich um einen regulären Domainnamen handeln würde. Wie Sie sehen können, übergeben wir innerhalb unseres Serverblocks alle anexample.com/proxy-me/... gestellten Anforderungen an den oben definierten Pool. Innerhalb dieses Pools wird ein Host ausgewählt, indem ein konfigurierbarer Algorithmus angewendet wird. Standardmäßig ist dies nur ein einfacher Round-Robin-Auswahlprozess (jede Anforderung wird nacheinander an einen anderen Host weitergeleitet).

Ändern des Upstream-Balancing-Algorithmus

Sie können den vom Upstream-Pool verwendeten Ausgleichsalgorithmus ändern, indem Sie Anweisungen oder Flags in den Upstream-Kontext einfügen:

  • (round robin): Der Standardalgorithmus für den Lastausgleich, der verwendet wird, wenn keine anderen Ausgleichsanweisungen vorhanden sind. Jeder Server, der im Upstream-Kontext definiert ist, wird der Reihe nach Anforderungen übergeben.

  • least_conn: Gibt an, dass neue Verbindungen immer an das Backend mit der geringsten Anzahl aktiver Verbindungen übergeben werden sollen. Dies kann besonders in Situationen nützlich sein, in denen die Verbindungen zum Backend möglicherweise einige Zeit bestehen bleiben.

  • ip_hash: Dieser Ausgleichsalgorithmus verteilt Anforderungen basierend auf der IP-Adresse des Clients an verschiedene Server. Die ersten drei Oktette werden als Schlüssel verwendet, um den Server für die Verarbeitung der Anforderung zu bestimmen. Das Ergebnis ist, dass Clients in der Regel jedes Mal von demselben Server bedient werden, was die Sitzungskonsistenz verbessern kann.

  • hash: Dieser Ausgleichsalgorithmus wird hauptsächlich beim Memcached Proxy verwendet. Die Server werden basierend auf dem Wert eines willkürlich bereitgestellten Hash-Schlüssels aufgeteilt. Dies kann Text, Variablen oder eine Kombination sein. Dies ist die einzige Ausgleichsmethode, bei der der Benutzer Daten eingeben muss. Dies ist der Schlüssel, der für den Hash verwendet werden soll.

Wenn Sie den Auswuchtalgorithmus ändern, sieht der Block möglicherweise folgendermaßen aus:

# http context

upstream backend_hosts {

    least_conn;

    server host1.example.com;
    server host2.example.com;
    server host3.example.com;
}

. . .

Im obigen Beispiel wird der Server ausgewählt, der die wenigsten Verbindungen aufweist. Dieip_hash-Direktive könnte auf die gleiche Weise festgelegt werden, um eine bestimmte Menge an "Klebrigkeit" der Sitzung zu erhalten.

Für diehash-Methode müssen Sie den Schlüssel angeben, gegen den gehasht werden soll. Das kann alles sein, was du willst:

# http context

upstream backend_hosts {

    hash $remote_addr$remote_port consistent;

    server host1.example.com;
    server host2.example.com;
    server host3.example.com;
}

. . .

Im obigen Beispiel werden Anforderungen basierend auf dem Wert der Client-IP-Adresse und des Ports verteilt. Wir haben auch den optionalen Parameterconsistent hinzugefügt, der den ketama-konsistenten Hashing-Algorithmus implementiert. Grundsätzlich bedeutet dies, dass sich Änderungen an Ihren Upstream-Servern nur minimal auf Ihren Cache auswirken.

Festlegen der Servergewichtung für den Ausgleich

In Deklarationen der Backend-Server ist jeder Server standardmäßig gleich "gewichtet". Dies setzt voraus, dass jeder Server dieselbe Last bewältigen kann und sollte (unter Berücksichtigung der Auswirkungen der Ausgleichsalgorithmen). Sie können jedoch auch während der Deklaration ein alternatives Gewicht für Server festlegen:

# http context

upstream backend_hosts {
    server host1.example.com weight=3;
    server host2.example.com;
    server host3.example.com;
}

. . .

Im obigen Beispiel empfängthost1.example.com den dreifachen Datenverkehr wie die beiden anderen Server. Standardmäßig wird jedem Server eine Gewichtung von 1 zugewiesen.

Verwenden von Puffern zum Freigeben von Back-End-Servern

Ein Problem beim Proxying, das viele Benutzer betrifft, ist die Auswirkung auf die Leistung, wenn dem Prozess ein zusätzlicher Server hinzugefügt wird. In den meisten Fällen kann dies durch die Nutzung der Puffer- und Caching-Funktionen von Nginx weitgehend verringert werden.

Wenn Sie einen Proxy an einen anderen Server senden, wirkt sich die Geschwindigkeit von zwei verschiedenen Verbindungen auf die Erfahrung des Clients aus:

  • Die Verbindung vom Client zum Nginx-Proxy.

  • Die Verbindung vom Nginx-Proxy zum Backend-Server.

Nginx kann sein Verhalten basierend auf einer dieser Verbindungen anpassen, die Sie optimieren möchten.

Ohne Puffer werden Daten vom Proxy-Server gesendet und sofort an den Client übertragen. Wenn angenommen wird, dass die Clients schnell sind, kann die Pufferung deaktiviert werden, um die Daten so schnell wie möglich an den Client zu senden. Mit Puffern speichert der Nginx-Proxy die Antwort des Backends vorübergehend und leitet diese Daten dann an den Client weiter. Wenn der Client langsam ist, kann der Nginx-Server die Verbindung zum Backend früher trennen. Es kann dann die Verteilung der Daten an den Client in beliebiger Geschwindigkeit durchführen.

Nginx verwendet standardmäßig ein Pufferdesign, da Clients in der Regel sehr unterschiedliche Verbindungsgeschwindigkeiten aufweisen. Wir können das Pufferverhalten mit den folgenden Anweisungen anpassen. Diese können in den Kontexten http, server oder location festgelegt werden. Es ist wichtig zu beachten, dass die Größenanweisungenper request konfiguriert sind. Wenn Sie sie also über Ihre Anforderungen hinaus erhöhen, kann dies Ihre Leistung beeinträchtigen, wenn viele Clientanforderungen vorliegen:

  • proxy_buffering: Diese Anweisung steuert, ob die Pufferung für diesen Kontext und untergeordnete Kontexte aktiviert ist. Standardmäßig ist diese Option aktiviert.

  • proxy_buffers: Diese Anweisung steuert die Anzahl (erstes Argument) und die Größe (zweites Argument) der Puffer für Proxy-Antworten. Standardmäßig werden 8 Puffer mit einer Größe konfiguriert, die einer Speicherseite entspricht (entweder4k oder8k). Durch Erhöhen der Anzahl der Puffer können Sie mehr Informationen puffern.

  • proxy_buffer_size: Der erste Teil der Antwort von einem Backend-Server, der Header enthält, wird getrennt vom Rest der Antwort gepuffert. Diese Anweisung legt die Größe des Puffers für diesen Teil der Antwort fest. Standardmäßig hat dies die gleiche Größe wieproxy_buffers. Da dies jedoch für Header-Informationen verwendet wird, kann dies normalerweise auf einen niedrigeren Wert eingestellt werden.

  • proxy_busy_buffers_size: Diese Anweisung legt die maximale Größe von Puffern fest, die als "clientfähig" und damit belegt markiert werden können. Während ein Client nur die Daten von jeweils einem Puffer lesen kann, werden Puffer in eine Warteschlange gestellt, um sie in Gruppen an den Client zu senden. Diese Anweisung steuert die Größe des Pufferbereichs, der in diesem Zustand sein darf.

  • proxy_max_temp_file_size: Dies ist die maximale Größe pro Anforderung für eine temporäre Datei auf der Festplatte. Diese werden erstellt, wenn die Upstream-Antwort zu groß ist, um in einen Puffer zu passen.

  • proxy_temp_file_write_size: Dies ist die Datenmenge, die Nginx gleichzeitig in die temporäre Datei schreibt, wenn die Antwort des Proxyservers für die konfigurierten Puffer zu groß ist.

  • proxy_temp_path: Dies ist der Pfad zu dem Bereich auf der Festplatte, in dem Nginx temporäre Dateien speichern soll, wenn die Antwort vom Upstream-Server nicht in die konfigurierten Puffer passt.

Wie Sie sehen, bietet Nginx eine Reihe verschiedener Anweisungen, um das Pufferverhalten zu optimieren. In den meisten Fällen müssen Sie sich nicht um die meisten dieser Werte kümmern, es kann jedoch nützlich sein, einige dieser Werte anzupassen. Am nützlichsten sind wahrscheinlich die Anweisungenproxy_buffers undproxy_buffer_size.

Ein Beispiel, das die Anzahl der verfügbaren Proxy-Puffer für jede vorgelagerte Anforderung erhöht, während der Puffer, in dem die Header wahrscheinlich gespeichert sind, verkleinert wird, sieht folgendermaßen aus:

# server context

proxy_buffering on;
proxy_buffer_size 1k;
proxy_buffers 24 4k;
proxy_busy_buffers_size 8k;
proxy_max_temp_file_size 2048m;
proxy_temp_file_write_size 32k;

location / {
    proxy_pass http://example.com;
}

Wenn Sie dagegen schnelle Clients haben, für die Sie sofort Daten bereitstellen möchten, können Sie die Pufferung vollständig deaktivieren. Nginx verwendet tatsächlich noch Puffer, wenn der Upstream schneller als der Client ist, versucht jedoch sofort, Daten an den Client zu senden, anstatt auf den Pool des Puffers zu warten. Wenn der Client langsam ist, kann dies dazu führen, dass die Upstream-Verbindung geöffnet bleibt, bis der Client aufholen kann. Wenn die Pufferung deaktiviert ist, wird nur der Puffer verwendet, der durch die Anweisungproxy_buffer_sizedefiniert ist:

# server context

proxy_buffering off;
proxy_buffer_size 4k;

location / {
    proxy_pass http://example.com;
}

Hochverfügbarkeit (optional)

Nginx-Proxys können durch Hinzufügen eines redundanten Satzes von Load Balancern robuster gemacht werden, wodurch eine Infrastruktur mit hoher Verfügbarkeit entsteht.

Einhigh availability (HA) -Einrichtung ist eine Infrastruktur ohne einen einzigen Fehlerpunkt, und Ihre Load Balancer sind Teil dieser Konfiguration. Durch die Verwendung von mehr als einem Load Balancer verhindern Sie mögliche Ausfallzeiten, wenn Ihr Load Balancer nicht verfügbar ist oder Sie ihn zur Wartung ausschalten müssen.

Hier ist ein Diagramm eines grundlegenden Hochverfügbarkeits-Setups:

HA Setup

In diesem Beispiel haben Sie mehrere Load Balancer (einen aktiven und einen oder mehrere passive) hinter einer statischen IP-Adresse, die von einem Server auf einen anderen neu zugeordnet werden können. Clientanforderungen werden von der statischen IP an den aktiven Lastenausgleich weitergeleitet und dann an Ihre Back-End-Server. Um mehr zu erfahren, lesen Siethis section of How To Use Floating IPs.

Proxy-Caching konfigurieren, um die Antwortzeiten zu verkürzen

Zwar kann das Puffern dazu beitragen, den Back-End-Server für die Verarbeitung weiterer Anforderungen freizugeben, Nginx bietet jedoch auch die Möglichkeit, Inhalte von Back-End-Servern zwischenzuspeichern, sodass für viele Anforderungen überhaupt keine Verbindung zum Upstream hergestellt werden muss.

Proxy-Cache konfigurieren

Um einen Cache für Proxy-Inhalte einzurichten, können Sie die Direktiveproxy_cache_pathverwenden. Dadurch wird ein Bereich erstellt, in dem die von den Proxy-Servern zurückgegebenen Daten gespeichert werden können. Die Direktiveproxy_cache_pathmuss im http-Kontext festgelegt werden.

Im folgenden Beispiel konfigurieren wir diese und einige verwandte Anweisungen, um unser Caching-System einzurichten.

# http context

proxy_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=backcache:8m max_size=50m;
proxy_cache_key "$scheme$request_method$host$request_uri$is_args$args";
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;

Mit der Direktiveproxy_cache_pathhaben wir ein Verzeichnis im Dateisystem definiert, in dem wir unseren Cache speichern möchten. In diesem Beispiel haben wir das Verzeichnis/var/lib/nginx/cacheausgewählt. Wenn dieses Verzeichnis nicht vorhanden ist, können Sie es mit der richtigen Berechtigung und Eigentümerschaft erstellen, indem Sie Folgendes eingeben:

sudo mkdir -p /var/lib/nginx/cache
sudo chown www-data /var/lib/nginx/cache
sudo chmod 700 /var/lib/nginx/cache

Der Parameterlevels= gibt an, wie der Cache organisiert wird. Nginx erstellt einen Cache-Schlüssel durch Hashing des Werts eines Schlüssels (unten konfiguriert). Die Ebenen, die wir oben ausgewählt haben, legen fest, dass ein einzelnes Zeichenverzeichnis (dies ist das letzte Zeichen des Hash-Werts) mit einem Unterverzeichnis aus zwei Zeichen (aus den nächsten beiden Zeichen am Ende des Hash-Werts) erstellt wird. Normalerweise müssen Sie sich nicht mit den Einzelheiten befassen, aber Nginx kann so schnell die relevanten Werte finden.

Der Parameterkeys_zone= definiert den Namen für diese Cache-Zone, die wirbackcache genannt haben. Hier legen wir auch fest, wie viele Metadaten gespeichert werden sollen. In diesem Fall speichern wir 8 MB Schlüssel. Pro Megabyte kann Nginx rund 8000 Einträge speichern. Der Parametermax_size legt die maximale Größe der tatsächlich zwischengespeicherten Daten fest.

Eine andere Anweisung, die wir oben verwenden, istproxy_cache_key. Hiermit wird der Schlüssel festgelegt, mit dem zwischengespeicherte Werte gespeichert werden. Mit demselben Schlüssel wird geprüft, ob eine Anforderung aus dem Cache bedient werden kann. Wir setzen dies auf eine Kombination aus dem Schema (http oder https), der HTTP-Anforderungsmethode sowie dem angeforderten Host und der angeforderten URI.

Die Direktiveproxy_cache_validkann mehrfach angegeben werden. Damit können wir konfigurieren, wie lange Werte in Abhängigkeit vom Statuscode gespeichert werden sollen. In unserem Beispiel speichern wir Erfolge und Weiterleitungen für 10 Minuten und löschen den Cache für jede Minute für 404 Antworten.

Jetzt haben wir die Cache-Zone konfiguriert, müssen Nginx jedoch mitteilen, wann der Cache verwendet werden soll.

An Orten, an denen wir ein Proxy für ein Backend erstellen, können wir die Verwendung dieses Caches konfigurieren:

# server context

location /proxy-me {
    proxy_cache backcache;
    proxy_cache_bypass $http_cache_control;
    add_header X-Proxy-Cache $upstream_cache_status;

    proxy_pass http://backend;
}

. . .

Mit der Direktiveproxy_cache können wir festlegen, dass die Cache-Zonebackcachefür diesen Kontext verwendet werden soll. Nginx prüft hier, ob ein Eintrag gültig ist, bevor es zum Backend weitergeleitet wird.

Die Direktiveproxy_cache_bypass wird auf die Variable$http_cache_control gesetzt. Dies enthält einen Indikator dafür, ob der Client explizit eine neue, nicht zwischengespeicherte Version der Ressource anfordert. Durch das Festlegen dieser Anweisung kann Nginx diese Arten von Clientanforderungen korrekt verarbeiten. Es ist keine weitere Konfiguration erforderlich.

Wir haben auch einen zusätzlichen Header namensX-Proxy-Cache hinzugefügt. Wir setzen diesen Header auf den Wert der Variablen$upstream_cache_status. Grundsätzlich wird ein Header gesetzt, der es uns ermöglicht, zu sehen, ob die Anforderung zu einem Cache-Treffer, einem Cache-Fehlschlag oder einer expliziten Umgehung des Cache geführt hat. Dies ist besonders beim Debuggen von Nutzen, bietet aber auch nützliche Informationen für den Client.

Hinweise zu Caching-Ergebnissen

Durch das Zwischenspeichern kann die Leistung Ihres Proxys erheblich verbessert werden. Bei der Konfiguration des Caches sind jedoch einige Punkte zu beachten.

Zunächst sollten alle benutzerbezogenen Datennotzwischengespeichert werden. Dies kann dazu führen, dass die Daten eines Benutzers einem anderen Benutzer angezeigt werden. Wenn Ihre Site vollständig statisch ist, ist dies wahrscheinlich kein Problem.

Wenn Ihre Site über einige dynamische Elemente verfügt, müssen Sie dies auf den Back-End-Servern berücksichtigen. Wie Sie damit umgehen, hängt davon ab, welche Anwendung oder welcher Server die Backend-Verarbeitung durchführt. Für privaten Inhalt sollten Sie den Header vonCache-Controlje nach Art der Daten auf "kein Cache", "kein Speicher" oder "privat" setzen:

  • no-cache: Gibt an, dass die Antwort nicht erneut zugestellt werden soll, ohne zuvor zu überprüfen, ob sich die Daten im Backend nicht geändert haben. Dies kann verwendet werden, wenn die Daten dynamisch und wichtig sind. Bei jeder Anforderung wird ein ETag-Hash-Metadaten-Header überprüft, und der vorherige Wert kann geliefert werden, wenn das Back-End denselben Hash-Wert zurückgibt.

  • no-store: Gibt an, dass die empfangenen Daten zu keinem Zeitpunkt zwischengespeichert werden dürfen. Dies ist die sicherste Option für private Daten, da die Daten jedes Mal vom Server abgerufen werden müssen.

  • private: Dies gibt an, dass kein gemeinsam genutzter Cache-Speicherplatz diese Daten zwischenspeichern soll. Dies kann nützlich sein, um anzuzeigen, dass der Browser eines Benutzers die Daten zwischenspeichern kann, der Proxy-Server sollte diese Daten jedoch nicht für spätere Anforderungen als gültig betrachten.

  • public: Dies zeigt an, dass es sich bei der Antwort um öffentliche Daten handelt, die an jedem Punkt der Verbindung zwischengespeichert werden können.

Ein verwandter Header, der dieses Verhalten steuern kann, ist dermax-age-Header, der die Anzahl der Sekunden angibt, in denen eine Ressource zwischengespeichert werden soll.

Wenn Sie diese Header je nach Empfindlichkeit des Inhalts richtig einstellen, können Sie den Cache besser nutzen und gleichzeitig die Sicherheit Ihrer privaten Daten sowie die Aktualität Ihrer dynamischen Daten gewährleisten.

Wenn Ihr Backend auch Nginx verwendet, können Sie einige davon mithilfe der Direktiveexpires festlegen, mit dermax-age fürCache-Control festgelegt werden:

location / {
    expires 60m;
}

location /check-me {
    expires -1;
}

Im obigen Beispiel ermöglicht der erste Block das Zwischenspeichern von Inhalten für eine Stunde. Der zweite Block setzt den Header vonCache-Controlauf "no-cache". Um andere Werte festzulegen, können Sie die Direktiveadd_headerwie folgt verwenden:

location /private {
    expires -1;
    add_header Cache-Control "no-store";
}

Fazit

Nginx ist in erster Linie ein Reverse-Proxy, der auch als Webserver fungieren kann. Aufgrund dieser Entwurfsentscheidung ist das Weiterleiten von Anforderungen an andere Server ziemlich einfach. Nginx ist jedoch sehr flexibel und ermöglicht auf Wunsch eine komplexere Kontrolle über Ihre Proxy-Konfiguration.