Was macht proxy_send_timeout wirklich in Nginx?

Was macht proxy_send_timeout wirklich in Nginx?

In der Nginx-Dokumentation gibt es Anweisungen zu drei verschiedenen Timeouts, die für „Backend“-Server wie folgt konfiguriert werden können:

proxy_connect_timeoutDefiniert ein Timeout für den Verbindungsaufbau mit einem Proxy-Server. Dabei ist zu beachten, dass dieses Timeout im Normalfall 75 Sekunden nicht überschreiten darf.

Das ist leicht zu verstehen: Nginx versucht, eine Verbindung zu einem Upstream-Backend-Server herzustellen. Wenn dies innerhalb einer bestimmten Zeitspanne nicht gelingt, gibt es auf und gibt einen Fehler zurück. Der Server ist nicht erreichbar, hat zu viele Verbindungen usw.

proxy_read_timeoutDefiniert ein Timeout für das Lesen einer Antwort vom Proxy-Server. Das Timeout wird nur zwischen zwei aufeinanderfolgenden Lesevorgängen festgelegt, nicht für die Übertragung der gesamten Antwort. Wenn der Proxy-Server innerhalb dieser Zeit nichts überträgt, wird die Verbindung geschlossen.

Das ist auch sinnvoll: Nginx hat bereits eine TCP-Verbindung mit dem „Backend“-Server hergestellt und ist nun dabei, die Anfrage tatsächlich zu senden, aber der Server benötigt viel Zeit für die Verarbeitung. Wenn die Verarbeitung länger als X Zeit dauert, wird die Verbindung geschlossen und die Anfrage wird an den Benutzer zurückgesendet.

Ich war tatsächlich überrascht, dass Nginx die Verbindung schließt. Ich dachte, es würde die Verbindung aufrechterhalten, aber einen Fehler an den Benutzer zurückgeben. Es klingt teuer, diese „Backend“-TCP-Verbindungen jedes Mal neu herzustellen, wenn etwas abläuft.

proxy_send_timeoutLegt ein Timeout für die Übermittlung einer Anfrage an den Proxy-Server fest. Das Timeout wird nur zwischen zwei aufeinanderfolgenden Schreibvorgängen festgelegt, nicht für die Übermittlung der gesamten Anfrage. Wenn der Proxy-Server innerhalb dieser Zeit nichts empfängt, wird die Verbindung geschlossen.

Das verstehe ich nicht ganz. Ich habe zwar eine Theorie, aber ich möchte, dass sie jemand bestätigt. Der einzige Wert, der mir für dieses Timeout einfällt, ist, wenn die Nutzlast der Anfrage riesig ist (z. B. eine große POST-Anfrage mit JSON oder ein Dokument, das der Benutzer speichern möchte). Um die Anfrage an das „Backend“ zu übertragen, muss die Anfrage in kleinere MTU-TCP-Segmente aufgeteilt und diese als „Blöcke“ der ursprünglichen Anfrage gesendet werden. Technisch gesehen haben wir die Anfrage also erst gesendet, als wir alle Blöcke erfolgreich an den Server übertragen haben. Misst Nginx die Zeit zwischen den einzelnen Blöcken der Anfrage? Ist das, was „Schreiben“ in der Dokumentation bedeutet? Sobald die Anfrage tatsächlich gesendet wurde, beginnt Nginx mit der Messung proxy_read_timeout?

Antwort1

TCP/IP ist ein sogenanntes „Streaming“-Datenübertragungsprotokoll. Es ist so konzipiert, dass der Teilnehmer, der Daten über eine TCP/IP-Verbindung liest, sich nicht unbedingt um die Größe von „Segmenten“ oder sogar Paketen kümmern muss. In der Praxis bedeutet dies, dass ein Peer eine traditionelle „Lese“-Operation ausführt, um Daten abzurufen, die vom Remote-Peer gesendet wurden (z. B.readmit Linux), liest nicht unbedingt auf einmal genau so viele Daten, wie das Remote-Ende für einen einzelnen "Schreib"-Vorgang bereitgestellt hat. Die TCP/IP-Protokollimplementierung erstellt ausnahmslos IP-Pakete mit angemessener Größe aus dem, was zu einem Zeitpunkt an einen "Schreib"-Vorgang übergeben wurde, und die Implementierung am anderen Ende stellt die Daten aus diesen Paketen wieder zusammen; aber sie wird nichtÜbergeben Sie sie unbedingt an eine „lesende“ Client-Anwendung mit denselben Datengrenzen!

Beispiel: A muss für jedes externe Systemereignis 50 KB Daten senden, so viele, dass sie nicht alle gleichzeitig in den RAM passen. Daher sendet er sie in Blöcken von 16 KB, was der Größe seines Sendepuffers entspricht. Er sendet also zuerst 16 KB, dann weitere 16 KB, dann weitere 16 KB und schließlich 2 KB. Die TCP/IP-Implementierung sendet diese 50 KB möglicherweise, gepuffert in einem internen 128-KB-Puffer (z. B. einem Kernelpuffer), und sendet sie erst dann über das Netzwerk, das ebenfalls seine eigenen Bedingungen hat. Einige dieser Daten, die auf eine Weise fragmentiert sind, die der sendenden Anwendung nicht einmal bewusst ist, kommen aufgrund der Netzwerkbedingungen zuerst am anderen Ende an und werden dort von der TCP/IP-Implementierung zusammengesetzt und erneut in einen Kernelpuffer gelegt. Der Kernel weckt den Prozess, der die Daten lesen möchte – und liest alle 30 KB davon. Der Empfänger muss entscheiden, ob er mehr erwartet und wie er damit umgehen soll, wie viel mehr er erwartet – derFormatder „Nachricht“ oder der Daten ist für TCP/IP kein Thema.

readDies bedeutet, dass Nginx beispielsweise nicht wissen kann, wie viele Anfragen eines Clients es bei jedem Aufruf auf einem Linux-basierten System auf einmal lesen wird .

Die Dokumentation gibt proxy_send_timeoutjedoch leicht Hinweise darauf, wozu es dient (Hervorhebung von mir):

Legt ein Timeout für die Übermittlung einer Anfrage an den Proxy-Server fest. Das Timeout wird nur zwischen zwei aufeinanderfolgenden Schreibvorgängen festgelegt, nicht für die Übermittlung der gesamten Anfrage.Wenn der Proxy-Server innerhalb dieser Zeit nichts empfängt, wird die Verbindung geschlossen.

Die Sache ist, seit NginxProxyseine Anfrage - was bedeutet, dass die Anfrage nichtentstehendamit - es wartet darauf, dass der „Downstream“-Client (das Remote-Ende der Verbindung, die die Anforderung an Nginx gesendet hat, die dieser in seiner Rolle als „Proxy“ nun nach oben weiterleiten soll) Daten der Anforderung überträgt, bevor er sie über die Upstream-Verbindung weiterleitet (schreibt).

So wie ich das verstehe, empfängt der Proxy-Server auch nichts, wenn [während des Timeout-Zeitraums] nichts vom Downstream empfangen wird – und die Verbindung wird dann geschlossen.

Anders ausgedrückt: Wenn der Downstream innerhalb der durch angegebenen Zeitspanne nichts sendet proxy_send_timeout, schließt Nginx die Verbindung mit dem Upstream.

Stellen Sie sich beispielsweise einen Webbrowser vor, der eine Anfrage an Nginx sendet. Der erste Teil wird von Nginx zum Zeitpunkt A gelesen. Unter der Annahme, dass er die Anfrage an einen Upstream weiterleitet, öffnet er eine Verbindung zu diesem Upstream und überträgt (schreibt), was er vom Browser erhalten hat, über den Upstream-Verbindungssocket. Er wartet dann einfach darauf, dass weitere Teile der Anfragedaten vom Browser gelesen werden – wenn der nächste Teil nach einer bestimmten Zeitüberschreitung X relativ zur Zeit A nicht eintrifft, schließt er die Verbindung zum Upstream.

Beachten Sie, dass dies nicht unbedingt bedeutet, dass die Verbindung zum Webbrowser geschlossen wird. Es wird sicherlich ein HTTP-Fehlerstatuscode für die Anforderung zurückgegeben, aber die Lebensdauer der Webbrowser-Verbindung wird von anderen Bedingungen bestimmt als proxy_send_timeout– Letzteres betrifft nur die Verbindungen von Nginx zum Upstream.

verwandte Informationen