In Bezug auf das Nginx-Panikproblem müssen wir zunächst verstehen, dass der Masterprozess während des Nginx-Startvorgangs die in der Konfigurationsdatei angegebenen Ports abhört und dann die Methode fork () aufruft, um jeden untergeordneten Prozess zu erstellen. Gemäß dem Arbeitsprinzip des Prozesses erbt der untergeordnete Prozess alle Speicherdaten und die Abhörports des übergeordneten Prozesses, was bedeutet, dass der Worker-Prozess nach dem Start auch jeden Port abhört. In Bezug auf den Herdenschock bedeutet dies, dass, wenn ein Client eine neue Verbindung anfordert, dieser das Verbindungsaufbauereignis jedes Arbeitsprozesses auslöst, jedoch nur ein Arbeitsprozess das Ereignis normal verarbeiten kann und die anderen Arbeitsprozesses feststellen, dass das Ereignis abgelaufen ist, und daher erneut in den Wartezustand wechseln. Dieses Phänomen, bei dem alle Arbeitsprozesse aufgrund eines Ereignisses „aufgeschreckt“ werden, wird als Herdenschreckproblem bezeichnet. Wenn alle Arbeitsprozesse ausgelöst werden, werden natürlich viele Ressourcen verbraucht. In diesem Artikel wird hauptsächlich erläutert, wie Nginx mit dem Herdenproblem umgeht. 1. Lösung Im vorherigen Artikel haben wir erwähnt, dass beim Erstellen jedes Arbeitsprozesses die Methode ngx_worker_process_init () aufgerufen wird, um den aktuellen Arbeitsprozess zu initialisieren. In diesem Prozess gibt es einen sehr wichtigen Schritt, nämlich, dass jeder Arbeitsprozess die Methode epoll_create () aufruft, um einen eindeutigen Epoll-Handle für sich selbst zu erstellen. Für jeden Port, der abgehört werden muss, gibt es einen entsprechenden Dateideskriptor. Der Worker-Prozess fügt den Dateideskriptor nur über die Methode epoll_ctl() zum Epoll-Handle des aktuellen Prozesses hinzu und wartet auf das Accept-Ereignis. Erst dann wird er durch das Verbindungsaufbauereignis des Clients ausgelöst und verarbeitet das Ereignis. Hier ist auch ersichtlich, dass das entsprechende Ereignis nicht ausgelöst werden kann, wenn der Worker-Prozess dem Epoll-Handle des Prozesses nicht den Dateideskriptor hinzufügt, der dem abzuhörenden Port entspricht. Basierend auf diesem Prinzip verwendet nginx eine gemeinsame Sperre, um zu steuern, ob der aktuelle Prozess die Berechtigung hat, den zu überwachenden Port zum Epoll-Handle des aktuellen Prozesses hinzuzufügen. Mit anderen Worten: Nur der Prozess, der die Sperre erhält, überwacht den Zielport. Auf diese Weise wird sichergestellt, dass bei jedem Auftreten eines Ereignisses nur ein Worker-Prozess ausgelöst wird. Die folgende Abbildung zeigt ein schematisches Diagramm des Arbeitszyklus des Worker-Prozesses: Zu dem Prozess in der Abbildung muss erklärt werden, dass jeder Worker-Prozess nach dem Eintritt in die Schleife versucht, die gemeinsame Sperre zu erhalten. Wenn dies nicht gelingt, wird der Dateideskriptor des überwachten Ports aus dem Epoll-Handle des aktuellen Prozesses entfernt (selbst wenn er nicht existiert). Der Hauptzweck dieser Vorgehensweise besteht darin, den Verlust von Client-Verbindungsereignissen zu verhindern. Auch wenn dies ein kleines Panikproblem verursachen kann, ist es nicht schwerwiegend. Stellen Sie sich vor, dass der Dateideskriptor des überwachten Ports theoretisch aus dem Epoll-Handle entfernt wird, wenn der aktuelle Prozess die Sperre aufhebt. Bevor der nächste Worker-Prozess die Sperre erhält, werden die jedem Port entsprechenden Dateideskriptoren während dieser Zeit von keinem Epoll-Handle überwacht, was zum Verlust von Ereignissen führt. Wenn andererseits die überwachten Dateideskriptoren nur entfernt werden, wenn der Erwerb der Sperre fehlschlägt, wie in der Abbildung gezeigt, bedeutet dies, dass es einen Prozess geben muss, der diese Dateideskriptoren bereits abgehört hat, sodass sie zu diesem Zeitpunkt sicher entfernt werden können, da der Erwerb der Sperre fehlschlägt. Dies führt jedoch zu einem Problem: Gemäß der obigen Abbildung gibt der aktuelle Prozess, wenn er eine Schleife abschließt, die Sperre frei und verarbeitet dann andere Ereignisse. Beachten Sie, dass der überwachte Dateideskriptor während dieses Vorgangs nicht freigegeben wird. Wenn zu diesem Zeitpunkt ein anderer Prozess die Sperre erhält und den Dateideskriptor abhört, gibt es zwei Prozesse, die den Dateideskriptor abhören. Wenn daher auf dem Client ein Verbindungsaufbauereignis auftritt, werden zwei Arbeitsprozesse ausgelöst. Dieses Problem ist aus zwei Hauptgründen tolerierbar:
2. Quellcode-Erklärung Die Methode zum Initialisieren des Ereignisses des Arbeitsprozesses wird hauptsächlich in der Methode ngx_process_events_and_timers() ausgeführt. Schauen wir uns an, wie diese Methode den gesamten Prozess handhabt. Das Folgende ist der Quellcode dieser Methode: void ngx_process_events_and_timers(ngx_cycle_t *cycle) { ngx_uint_t-Flags; ngx_msec_t-Zeitgeber, Delta; wenn (ngx_trylock_accept_mutex(Zyklus) == NGX_ERROR) { zurückkehren; } // Beginnen Sie hier mit der Verarbeitung von Ereignissen. Beim kqueue-Modell verweist es auf die Methode ngx_kqueue_process_events(). // Für das Epoll-Modell verweist es auf die Methode ngx_epoll_process_events() // Die Hauptfunktion dieser Methode besteht darin, die Ereignisliste im entsprechenden Ereignismodell abzurufen und das Ereignis dann zu ngx_posted_accept_events hinzuzufügen // Warteschlange oder ngx_posted_events-Warteschlange (leer) ngx_process_events (Zyklus, Timer, Flags); // Beginnen Sie hier mit der Verarbeitung des Accept-Ereignisses und übergeben Sie es an die Methode ngx_event_accept() von ngx_event_accept.c; ngx_event_process_posted(Zyklus, &ngx_posted_accept_events); // Beginnen Sie mit der Freigabe der Sperre, wenn (ngx_accept_mutex_held) { ngx_shmtx_unlock(&ngx_accept_mutex); } // Wenn es nicht in der Ereigniswarteschlange verarbeitet werden muss, verarbeiten Sie das Ereignis direkt. // Bei der Ereignisverarbeitung wird es, wenn es sich um ein Akzeptanzereignis handelt, zur Verarbeitung an die Methode ngx_event_accept() von ngx_event_accept.c übergeben. // Wenn es sich um ein Leseereignis handelt, wird es von der Methode ngx_http_wait_request_handler() von ngx_http_request.c behandelt. // Ereignisse, die verarbeitet wurden, werden letztendlich von der Methode ngx_http_keepalive_handler() von ngx_http_request.c behandelt. // Beginnen Sie mit der Verarbeitung anderer Ereignisse außer dem Akzeptanzereignis ngx_event_process_posted(cycle, &ngx_posted_events); } Im obigen Code haben wir den Großteil der Prüfarbeit weggelassen und nur den Skelettcode belassen. Zuerst ruft der Worker-Prozess die Methode ngx_trylock_accept_mutex() auf, um die Sperre zu erhalten. Wenn die Sperre erhalten wurde, hört er auf die Dateideskriptoren, die den einzelnen Ports entsprechen. Anschließend wird die Methode ngx_process_events() aufgerufen, um die im Epoll-Handle überwachten Ereignisse zu verarbeiten. Anschließend wird die gemeinsame Sperre aufgehoben und abschließend die Lese- und Schreibereignisse der verbundenen Clients abgearbeitet. Sehen wir uns an, wie die Methode ngx_trylock_accept_mutex() eine gemeinsame Sperre erwirbt: ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *Zyklus) { // Versuchen Sie, den CAS-Algorithmus zu verwenden, um eine gemeinsame Sperre zu erhalten, wenn (ngx_shmtx_trylock(&ngx_accept_mutex)) { // ngx_accept_mutex_held ist 1, was bedeutet, dass der aktuelle Prozess die Sperre erhalten hat, wenn (ngx_accept_mutex_held && ngx_accept_events == 0) { gib NGX_OK zurück; } // Hier wird der Dateideskriptor der aktuellen Verbindung in der Warteschlange des entsprechenden Ereignisses registriert, beispielsweise im Array change_list des kqueue-Modells. // Wenn nginx jeden Worker-Prozess aktiviert, erbt der Worker-Prozess standardmäßig den vom Master-Prozess überwachten Socket-Handle. // Dies führt zu einem Problem, d. h. wenn ein Port ein Client-Ereignis aufweist, werden alle Prozesse aufgeweckt, die auf dem Port lauschen. // Allerdings kann nur ein Arbeitsprozess das Ereignis erfolgreich verarbeiten, und andere Prozesse stellen nach dem Aufwachen fest, dass das Ereignis abgelaufen ist. // Daher wird es weiterhin in den Wartezustand wechseln, der als „Herdenschock“-Phänomen bezeichnet wird. // Nginx löst das Herdenpanik-Phänomen hier durch die Methode der gemeinsamen Sperre, d. h. nur der Arbeitsprozess, der die Sperre erhält, kann // Client-Ereignisse verarbeiten. Tatsächlich fügt der Arbeitsprozess jedoch beim Erhalt der Sperre die Abhörereignisse jedes Ports für den aktuellen Arbeitsprozess erneut hinzu. // Andere Arbeitsprozesse führen keine Überwachung durch. Das heißt, dass an jedem Port gleichzeitig nur ein Arbeitsprozess lauscht. // Dadurch wird das Problem des „Herdenschocks“ vermieden. // Die Methode ngx_enable_accept_events() dient hier dazu, Abhörereignisse für jeden Port für den aktuellen Prozess erneut hinzuzufügen. wenn (ngx_enable_accept_events(Zyklus) == NGX_ERROR) { ngx_shmtx_unlock(&ngx_accept_mutex); gib NGX_ERROR zurück; } // Das Flag zeigt an, dass die Sperre erfolgreich erworben wurde ngx_accept_events = 0; ngx_accept_mutex_held = 1; gib NGX_OK zurück; } // Der Sperrvorgang ist zuvor fehlgeschlagen, daher müssen wir den Status von ngx_accept_mutex_held zurücksetzen und die Ereignisse der aktuellen Verbindung löschen, wenn (ngx_accept_mutex_held) { // Wenn der ngx_accept_mutex_held des aktuellen Prozesses 1 ist, setze ihn auf 0 zurück und lösche die Überwachungsereignisse // des aktuellen Prozesses auf jedem Port, wenn (ngx_disable_accept_events(cycle, 0) == NGX_ERROR) { gib NGX_ERROR zurück; } ngx_accept_mutex_held = 0; } gib NGX_OK zurück; } Im obigen Code werden im Wesentlichen drei Dinge erledigt:
3. Zusammenfassung In diesem Artikel werden zunächst die Ursachen des Herdenpanik-Phänomens erläutert, dann wird vorgestellt, wie nginx das Herdenpanik-Problem löst, und abschließend wird erläutert, wie nginx das Herdenpanik-Problem aus der Quellcode-Perspektive behandelt. 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. |
<<: Miniprogramm zur Implementierung der Rechnerfunktion
>>: Beispielanalyse der Auswirkungen des MySQL-Index auf die Sortierung
Installieren Sie JDK: Offizieller Oracle-Download...
Vorwort Derzeit ist das von meiner Firma verwende...
Alle folgenden Codes stehen zwischen <head>....
Anzeigen der abhängigen Bibliotheken von so oder ...
Jeder, der das Linux-System verwendet hat, sollte...
In diesem Artikel wird der spezifische Code von v...
Weiterleitung zwischen zwei verschiedenen Servern...
1. Methode 1 zum Löschen von Floating Legen Sie d...
Die erste Methode zur Parameterübergabe ist die d...
Lassen Sie mich Ihnen nun eine Frage stellen. Was...
In diesem Artikel wird der spezifische Code von j...
Was bedeutet Textfüllfarbe? Rein wörtlich bedeute...
Einführung: Ich glaube, dass jeder einige Dokumen...
Inhaltsverzeichnis Hintergrundbeschreibung Erstel...
Effektvorschau Ideen Scrollen Sie durch die aktue...