Heim  >  Artikel  >  Betrieb und Instandhaltung  >  So analysieren Sie den Gunicorn Arbiter-Quellcode

So analysieren Sie den Gunicorn Arbiter-Quellcode

PHPz
PHPznach vorne
2023-05-12 16:28:181381Durchsuche

Wie bereits erwähnt, ist Arbiter der Kern des Gunicorn-Master-Prozesses. Arbiter ist hauptsächlich für die Verwaltung von Worker-Prozessen verantwortlich, einschließlich des Startens, Überwachens und Beendens von Worker-Prozessen. Gleichzeitig kann Arbiter auch App-Anwendungen im laufenden Betrieb aktualisieren (neu laden) oder Gunicorn online aktualisieren, wenn bestimmte Signale auftreten. Der Kerncode von Arbiter befindet sich in einer Datei und die Codemenge ist nicht groß. Der Quellcode ist hier: https://github.com/benoitc/gunicorn.

Arbiter verfügt hauptsächlich über die folgenden Methoden:

setup:

Das Wichtigste ist, Konfigurationselemente zu verarbeiten Anzahl der Arbeiter und Arbeiter-Arbeitsmodell handle_xxx#🎜🎜 #:

Spezifische Verarbeitungsfunktionen für jedes Signal

kill_worker, kill_workers

:

Signale senden zum Worker-Prozess# 🎜🎜#spawn_worker, spawn_workers

:

Einen neuen Worker-Prozess forken

murder_workers # ?? # Worker basierend auf der Konfigurationsdatei. Die Anzahl sowie die Anzahl der aktuell aktiven Worker bestimmen, ob der Worker-Prozess geforkt oder beendet wird #

Empfangenes Signal SIGUSR2-Aufruf, Online-Upgrade von Gunicorn

Neuladen:

Nach dem Empfang des Signals SIGHUP-Aufruf wird der Worker-Prozess ausgeführt Der Prozess wird basierend auf der neuen Konfiguration gestartet und der vorherige Worker wird beendet die ausgewählte Zeitüberschreitung zum Schlafen und kann geweckt werden

run

Hauptschleife

Die einzigen Funktionen von Arbiter, die tatsächlich von anderen Codes (Anwendung) aufgerufen werden, sind __init__ und Laufmethoden. In einer Codezeile:

Arbiter(self).run()

Das Selbst im obigen Code ist das Anwendungsinstanz, in der __init__ Setup aufruft, um die Konfigurationselemente festzulegen. Das Folgende ist der Pseudocode der Ausführungsmethode

def run()
    self.init_signal()
    self.LISTENERS = create_sockets(self.cfg, self.log)
    self.manage_workers()    while True:        if no signal in SIG_QUEUE
            self.sleep()        else:
            handle_signal()

Über Fork Child Prozess#🎜🎜 #

Der Code für den untergeordneten Fork-Prozess befindet sich in spawn_worker. Der Quellcode lautet wie folgt:

Arbiter.spawn_worker Hauptprozess:

(1) worker_class laden und instanziieren (Standard ist das synchrone Modell SyncWorker)

(2) Der übergeordnete Prozess (Masterprozess) kehrt nach der Verzweigung zurück , und die gesamte nachfolgende Logik wird im untergeordneten Prozess ausgeführt # (4) Nachdem die Schleife beendet ist, rufen Sie sys.exit(0) auf # Das Folgende ist ein Teil des Codes, den ich selbst geschrieben habe. Der Haupt-Fork-Prozess ist vereinfacht 🎜#Ausgabe in der Testumgebung:

# 🎜🎜# Fork-Unterprozess 9601

Fork-Unterprozess 9602

Unterprozess wird beendet 9601 9600

Unterprozess wird beendet 9602 9600#🎜🎜 #

 Hauptprozess wird beendet 9600

Es ist zu beachten, dass Zeile 20

sys.exit aufruft
um das Ende des untergeordneten Prozesses sicherzustellen, andernfalls wird die Hauptfunktion fortgesetzt. Die for-Schleife und die nachfolgende Logik. Kommentieren Sie Zeile 19 aus und führen Sie sie erneut aus. Anhand der Ausgabe werden Sie es verstehen.

Über das Beenden des Unterprozesses

Es ist sehr einfach, den Arbeitsprozess zu beenden. Er sendet ein Signal direkt Der Quellcode lautet wie folgt:


 1 # prefork.py 2 import sys 3 import socket 4 import select 5 import os 6 import time 7   8 def do_sub_process(): 9     pid = os.fork()10     if pid < 0:11         print &#39;fork error&#39;12         sys.exit(-1)13     elif pid > 0:14         print 'fork sub process %d'  % pid15         return16  17     # must be child process18     time.sleep(1)19     print 'sub process will exit', os.getpid(), os.getppid()20     sys.exit(0)21  22 def main():23     sub_num = 224     for i in range(sub_num):25         do_sub_process()26     time.sleep(10)27     print 'main process will exit', os.getpid()28  29 if __name__ == '__main__':30     main()

Über Schlaf und Aufwachen#🎜🎜 #

us Werfen wir einen Blick auf Arbiters Schlaf und Aufwachen. Der Arbiter wird „schlafen“, wenn kein Signal zur Verarbeitung vorhanden ist. Natürlich ruft er time.sleep nicht auf, da das Signal sonst nicht sofort verarbeitet wird, wenn es eintrifft. Die Implementierung ist hier cleverer und verwendet Pipes und Select Timeout. Schauen Sie sich einfach den Code an und Sie werden es wissen

如何进行gunicorn Arbiter 源码解析

 1     def kill_worker(self, pid, sig): 2         """\ 3         Kill a worker 4  5         :attr pid: int, worker pid 6         :attr sig: `signal.SIG*` value 7          """ 8         try: 9             os.kill(pid, sig)10         except OSError as e:11             if e.errno == errno.ESRCH:12                 try:13                     worker = self.WORKERS.pop(pid)14                     worker.tmp.close()15                     self.cfg.worker_exit(self, worker)16                     return17                 except (KeyError, OSError):18                     return19             raise

Die Kommentare im Code sind sehr klar geschrieben, oder PIPE kann sofort gelesen und zurückgegeben werden, oder auf eine Zeitüberschreitung warten. Die Pipe ist lesbar, da ein Signal auftritt. Hier ist ein Blick auf die Pipe-Funktion

 os.pipe()

#🎜 🎜#

Erstellen Sie ein Paar Dateideskriptoren (r,w), die jeweils zum Lesen und Schreiben verwendet werden können.

#🎜 🎜# Schauen wir uns an, wann die Pipe lesbar ist: Es muss etwas in die Pipe geschrieben werden #:

Exit, INT: Schnelles Herunterfahren#. 🎜🎜#

LAUFZEIT: Ordentliches Herunterfahren. Wartet darauf, dass der Worker seine aktuelle Anforderung abschließt, bis eine Zeitüberschreitung auftritt.

HUP: Konfiguration neu laden, neue Arbeitsprozesse mit neuer Konfiguration starten und alte Arbeitsprozesse ordnungsgemäß herunterfahren. Gunicorn lädt die neue Version auch, wenn die Anwendung nicht vorinstalliert ist (mit der Option --preload).

TTIN: Erhöhen Sie die Anzahl der Prozesse um eins.

TTOU: Verringern Sie die Anzahl der Prozesse um eins.

USR1: Öffnen Sie die Protokolldatei erneut.

USR2: Aktualisieren Sie Gunicorn im Handumdrehen. Um den alten Prozess zu beenden, sollte ein separates Laufzeitsignal verwendet werden. Dieses Signal kann auch verwendet werden, um vorinstallierte neue Versionen der Anwendung zu verwenden.

Winch: Arbeitsprozesse ordnungsgemäß herunterfahren, wenn Gunicorn dämonisiert wird.

Das obige ist der detaillierte Inhalt vonSo analysieren Sie den Gunicorn Arbiter-Quellcode. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen