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

So erstellen Sie einen SSH-Dienst basierend auf einem Golang-Image in Docker

Nachfolgend finden Sie den Code zum Erstellen ein...

Detaillierte Erläuterung des Linux-CRM-Bereitstellungscodes

Linux-Grundkonfiguration Kompilieren und installi...

getdata Tabelle Tabellendaten Join MySQL-Methode

öffentliche Funktion json_product_list($where, $o...

Vue implementiert die Funktionen Vergrößern, Verkleinern und Ziehen

In diesem Artikelbeispiel wird der spezifische Co...

Beispielcode zum Erstellen eines Dropdown-Menüs mit reinem CSS

Einführung: Als ich mir in letzter Zeit die Frage...

Lösung für das Textüberlaufproblem auf CSS-Flex-Basis

Die unbedeutende flex-basis hat bei der kleinen F...

Anwendungsbeispiele für die try_files-Direktive von Nginx

Die Konfigurationssyntax von Nginx ist flexibel u...

7 Möglichkeiten, Elemente mit CSS vertikal zu zentrieren

【1】Kennen Sie die Breite und Höhe des zentrierten...