So implementieren Sie einen reibungslosen Neustart von Nginx

So implementieren Sie einen reibungslosen Neustart von Nginx

1. Hintergrund

Während des Serverentwicklungsprozesses ist es unvermeidlich, den Dienst neu zu starten, um neuen Code oder neue Konfigurationen zu laden. Wenn sichergestellt werden kann, dass der Dienst während des Serverneustarts nicht unterbrochen wird, können die Auswirkungen des Neustarts auf das Geschäft auf Null reduziert werden. Ich habe kürzlich zum Thema „Smooth Restart“ von Nginx recherchiert und fand es sehr interessant. Ich habe es aufgezeichnet, damit interessierte Studenten es lesen können.

2. Vorgang neu starten

  • Neustart bedeutet, das Alte durch das Neue zu ersetzen. Bei der Aufgabenübergabe werden der alte und der neue Server zwangsläufig koexistieren. Daher läuft der Neustartvorgang ungefähr wie folgt ab:
    • Einen neuen Server starten
    • Die alten und neuen Server existieren nebeneinander und verarbeiten gemeinsam Anfragen und stellen Dienste bereit.
    • Der alte Server wird nach der Verarbeitung aller Anfragen ordnungsgemäß beendet.
  • Das Hauptproblem besteht hier darin, sicherzustellen, dass der alte und der neue Server koexistieren können. Wenn die Server-Ports vor und nach dem Neustart gleich sind, wie kann sichergestellt werden, dass beide auf denselben Port hören können?

3. Nginx-Implementierung

Um den reibungslosen Neustart von nginx zu überprüfen, versuchte der Autor zunächst, beim Start von nginx erneut eine neue Serverinstanz zu starten. Das Ergebnis ist wie in der Abbildung dargestellt:

Offensichtlich funktioniert das erneute Öffnen der Serverinstanz nicht, da der alte und der neue Server denselben Port 80 verwenden. Wenn die Socket-Reuseport-Option zur Wiederverwendung von Ports nicht aktiviert ist, schlägt der Bind-Systemaufruf fehl. Standardmäßig versucht Nginx die Bindung fünfmal erneut und wird nach einem Fehler direkt beendet. Nginx muss auf die IPV4-Adresse 0.0.0.0 und die IPV6-Adresse [::] hören, daher werden in der Abbildung 10 Emerg-Protokolle ausgedruckt.

Als Nächstes versuchen wir den Befehl „Smooth Restart“, der aus zwei Befehlen besteht:

kill -USR2 `cat /var/run/nginx.pid`
kill -QUIT `cat /var/run/nginx.pid.oldbin`

Der erste Befehl sendet das USR2-Signal an den alten Masterprozess. Die PID des Prozesses wird in der Datei /var/run/nginx.pid gespeichert, wobei der Dateipfad nginx.pid von nginx.conf konfiguriert wird.

Der zweite Befehl sendet das Signal QUIT an den alten Masterprozess. Die PID des Prozesses wird in der Datei /var/run/nginx.pid.oldbin gespeichert und anschließend wird der alte Masterprozess beendet.

Die Frage ist also, warum die PID des alten Masterprozesses in zwei PID-Dateien vorhanden ist? Tatsächlich hat der alte Masterprozess nach dem Senden des USR2-Signals an den alten Masterprozess die PID umbenannt und die ursprüngliche Datei nginx.pid wurde in nginx.pid.oldbin umbenannt. Auf diese Weise kann der neue Master den Dateinamen nginx.pid verwenden.

Führen Sie zuerst den ersten Befehl aus. Das Ergebnis ist wie folgt:

Ja, die alten und neuen Master- und Worker-Prozesse koexistieren. Lassen Sie uns den zweiten Befehl ausführen. Das Ergebnis ist wie folgt:

Wie Sie sehen, wurden der alte Masterprozess 8527 und seine Arbeitsprozesse alle beendet, sodass nur der neue Masterprozess 12740 übrig blieb.

Ich frage mich, warum das manuelle Starten einer neuen Instanz nicht funktioniert, ein Neustart mit einem Signal jedoch schon. Schauen Sie sich zunächst die Nginx-Protokolldatei an:

Zusätzlich zum vorherigen Fehlerprotokoll gibt es noch einen Hinweis, der bedeutet, dass Sockets vererbt werden und die fd-Werte 6 und 7 sind. Ich habe dem Protokoll folgend den Nginx-Quellcode durchgesehen und die Funktion nginx.c/ngx_exec_new_binary gefunden.

ngx_pid_t
ngx_exec_new_binary(ngx_cycle_t *Zyklus, char *const *argv)
{
  ...
  ctx.Pfad = argv[0];
  ctx.name = "neuer Binärprozess";
  ctx.argv = argv;
  n = 2;
  Umgebung = ngx_set_environment(Zyklus, &n);
...
  var = ngx_alloc(Größe von (NGINX_VAR)
          + Zyklus->Listening.Nelts * (NGX_INT32_LEN + 1) + 2,
          Zyklus->Protokoll);
...
  p = ngx_cpymem(var, NGINX_VAR "=", Größe von(NGINX_VAR));
  ls = Zyklus->Zuhören.elts;
  für (i = 0; i < Zyklus->listening.nelts; i++) {
    p = ngx_sprintf(p, "%ud;", ls[i].fd);
  }
  *p = "\0";
  Umgebung[n++] = var;
...
  umgebung[n] = NULL;
...
  ctx.envp = (char *const *) env;
  ccf = (ngx_core_conf_t *) ngx_get_conf(Zyklus->conf_ctx, ngx_core_module);
  wenn (ngx_rename_file(ccf->pid.data, ccf->oldpid.data) == NGX_FILE_ERROR) {
    ...
    gib NGX_INVALID_PID zurück;
  }
  pid = ngx_execute(Zyklus, &ctx);
  wenn (pid == NGX_INVALID_PID) {
    wenn (ngx_rename_file(ccf->oldpid.data, ccf->pid.data)
      == NGX_FILE_ERROR)
    {
      ...
    }
  }
...
  pid zurückgeben;
}

Der Funktionsablauf ist

  1. Kopieren Sie alle vom alten Masterprozess überwachten FDS in die Umgebungsvariable NGINX_VAR des neuen Masterprozesses.
  2. umbenennen umbenennen pid datei
  3. Die Funktion ngx_execute verzweigt einen untergeordneten Prozess und execve führt die Befehlszeile aus, um einen neuen Server zu starten.
  4. Beim Serverstart wird die Umgebungsvariable NGINX_VAR analysiert. Der spezifische Code von ngx_connection.c/ngx_add_inherited_sockets lautet:
statisches ngx_int_t
ngx_add_inherited_sockets(ngx_cycle_t *Zyklus)
{
...
  geerbt = (u_char *) getenv(NGINX_VAR);
  wenn (geerbt == NULL) {
    gib NGX_OK zurück;
  }
  wenn (ngx_array_init(&cycle->listening, cycle->pool, 10,
            Größe von (ngx_listening_t))
    != NGX_OK)
  {
    gib NGX_ERROR zurück;
  }
  für (p = geerbt, v = p; *p; p++) {
    wenn (*p == ':' || *p == ';') {
      s = ngx_atoi(v, p - v);
      ...
      v = p + 1;
      ls = ngx_array_push(&cycle->listening);
      wenn (ls == NULL) {
        gib NGX_ERROR zurück;
      }
      ngx_memzero(ls, Größe von(ngx_listening_t));
      ls->fd = (ngx_socket_t) s;
    }
  }
  ...
  ngx_inherited = 1;
  gibt ngx_set_inherited_sockets(Zyklus) zurück;
}

Der Funktionsablauf ist:

Analysieren Sie den Wert der Umgebungsvariable NGINX_VAR und holen Sie sich den fd zum Speichern im Array

Der fd entsprechende Socket wird auf ngx_inherited gesetzt, um die Informationen dieser Sockets zu speichern.

Mit anderen Worten, der neue Server bindet den Abhörport überhaupt nicht neu. Diese fd-Zustände und -Werte werden übernommen, wenn der neue Masterprozess sich aufspaltet. Der neue Masterprozess kann die geerbten Dateideskriptoren abhören und verarbeiten. Der entscheidende Punkt hierbei ist, dass der Dateideskriptor des Abhörsockets über ENV übergeben wird.

Das Obige ist der vollständige Inhalt dieses Artikels. Ich hoffe, er wird für jedermanns Studium hilfreich sein. Ich hoffe auch, dass jeder 123WORDPRESS.COM unterstützen wird.

Das könnte Sie auch interessieren:
  • So implementieren Sie einen reibungslosen Neustart und ein Upgrade von Nginx
  • Detaillierte Vorgehensweise für ein reibungsloses Nginx-Upgrade
  • Die Version Nginx 1.8.0 wurde reibungslos auf die neue Version 1.9.7 aktualisiert
  • So führen Sie in 1 Minute ein reibungsloses Upgrade und Rollback der Nginx-Version durch
  • Detaillierte Erläuterung des Prozesses des reibungslosen Upgrades von Nginx
  • Grafisches Tutorial zum reibungslosen Neustart und Upgrade von Nginx

<<:  JS versteht die Zeitzonen GMT und UTC genau

>>:  MySQL-Techniken zum schnellen Datenvergleich

Artikel empfehlen

Vue implementiert das Senden von Emoticons im Chatfenster

Der spezifische Code zum Senden von Emoticons im ...

Beheben von Problemen mit hoher MySQL-CPU-Auslastung

Hohe CPU-Last durch MySQL Heute Nachmittag habe i...

Einfache Prinzipien für die Gestaltung des Webseiten-Layouts

Dieser Artikel fasst einige einfache Prinzipien d...

So fügen Sie MySQL Indizes hinzu

Hier ist eine kurze Einführung in Indizes: Der Zw...

Welche Vorteile bietet die Verwendung des B+-Baumindex in MySQL?

Bevor wir dieses Problem verstehen, schauen wir u...

HTML-Head-Tag-Metadaten zum Erreichen einer Aktualisierungsumleitung

Code kopieren Der Code lautet wie folgt: <html...

Die Verwendung von FrameLayout in sechs Layouts

Vorwort In der letzten Ausgabe haben wir Ihnen Li...

CSS-Code zum Erreichen eines Hintergrundverlaufs und automatischen Vollbilds

CSS-Probleme mit dem Hintergrundverlauf und dem a...

So fügen Sie eine Schnittstellen-Abhörmaske in ein Vue-Projekt ein

1. Geschäftshintergrund Die Verwendung einer Mask...

Ein umfassendes Verständnis der funktionalen Komponenten von Vue.js

Inhaltsverzeichnis Vorwort Funktionale React-Komp...

mysql5.7.21 UTF8-Kodierungsproblem und -Lösung in der Mac-Umgebung

1. Ziel: Ändern Sie den Wert des character_set_se...