Der gemeinsam genutzte Speicher von Nginx ist einer der Hauptgründe für die hohe Leistung und wird hauptsächlich zum Zwischenspeichern von Dateien verwendet. In diesem Artikel wird zunächst die Verwendung des gemeinsam genutzten Speichers erläutert und anschließend erläutert, wie Nginx den gemeinsam genutzten Speicher verwaltet. 1. Anwendungsbeispiele Die Anweisungen für Nginx zum Deklarieren des gemeinsam genutzten Speichers lauten: Proxy-Cache-Pfad /Benutzer/Mike/nginx-Cache-Level=1:2, Keys_Zone=eins:10 m, Max-Size=10 g, inaktiv=60 m, Use_Temp_Pfad=aus; Hier deklarieren wir einfach einen gemeinsam genutzten Speicher mit dem Namen „One“ mit einem maximal verfügbaren Speicher von 10 GB. Die Bedeutung der einzelnen Parameter ist hier wie folgt:
2. Funktionsprinzip Die Verwaltung des gemeinsam genutzten Speichers gliedert sich im Wesentlichen in mehrere Teile, wie in der folgenden Abbildung dargestellt: Wie Sie sehen, ist es hauptsächlich in mehrere Aspekte unterteilt, darunter Initialisierung, gemeinsame Speicherverwaltung, gemeinsames Laden des Speichers und gemeinsame Speichernutzung. Während des Initialisierungsprozesses wird zuerst die Anweisung proxy_cache_path analysiert und dann werden die Cache-Manager- und Cache-Loader-Prozesse gestartet. Der Cache-Manager-Prozess ist hauptsächlich für die Verwaltung des gemeinsam genutzten Speichers verantwortlich, der hauptsächlich abgelaufene Daten über den LRU-Algorithmus löscht oder bei knappen Ressourcen einige nicht referenzierte Speicherdaten zwangsweise löscht. Die Hauptaufgabe des Cache-Loader-Prozesses besteht darin, die vorhandenen Dateien im Dateispeicherverzeichnis zu lesen und sie nach dem Start von nginx in den gemeinsam genutzten Speicher zu laden. Der gemeinsam genutzte Speicher wird hauptsächlich zum Zwischenspeichern der Antwortdaten nach der Verarbeitung der Anforderung verwendet. Dieser Teil wird im folgenden Artikel erläutert. Dieser Artikel erläutert hauptsächlich die Funktionsprinzipien der ersten drei Teile. Gemäß der obigen Aufteilung kann die Verwaltung des gemeinsam genutzten Speichers in drei Teile unterteilt werden (die Verwendung des gemeinsam genutzten Speichers wird später erläutert). Nachfolgend sehen Sie ein schematisches Diagramm des Verarbeitungsablaufs dieser drei Teile: Wie aus dem obigen Flussdiagramm ersichtlich ist, besteht die Hauptarbeit im Hauptprozess darin, die Anweisung proxy_cache_path zu analysieren, den Cache-Manager-Prozess zu starten und den Cache-Loader-Prozess zu starten. Im Cache-Manager-Prozess ist die Hauptarbeit in zwei Teile unterteilt: 1. Überprüfen Sie, ob das Element am Ende der Warteschlange abgelaufen ist. Wenn es abgelaufen ist und der Referenzzähler 0 ist, löschen Sie das Element und die dem Element entsprechende Datei. 2. Überprüfen Sie, ob die aktuellen gemeinsam genutzten Speicherressourcen knapp sind. Wenn die Ressourcen knapp sind, löschen Sie alle Elemente und ihre Dateien mit einem Referenzzähler von 0, unabhängig davon, ob sie abgelaufen sind. Im Verarbeitungsfluss des Cache-Loader-Prozesses werden die Dateien im Verzeichnis, in dem die Dateien gespeichert sind, und seinen Unterverzeichnissen rekursiv durchlaufen und diese Dateien dann in den gemeinsam genutzten Speicher geladen. Es ist zu beachten, dass der Cache-Manager-Prozess jedes Mal in die nächste Schleife eintritt, nachdem alle gemeinsam genutzten Speicherblöcke durchlaufen wurden, während der Cache-Loader-Prozess 60 Sekunden nach dem Start von nginx einmal ausgeführt wird und dann den Prozess beendet. 3. Quellcode-Interpretation 3.1 Analyse der Proxy_Cache_Path-Richtlinie Für die Analyse jeder nginx-Anweisung wird im entsprechenden Modul eine ngx_command_t-Struktur definiert. In der Struktur gibt es eine festgelegte Methode, die die Methode angibt, mit der die aktuelle Anweisung analysiert wird. Nachfolgend sehen Sie die Definition der ngx_command_t-Struktur, die dem Proxy_Cache_Path entspricht: statische ngx_command_t ngx_http_proxy_commands[] = { { ngx_string("proxy_cache_path"), // gibt den Namen der aktuellen Anweisung an // gibt den Ort an, an dem die aktuelle Anweisung verwendet wird, nämlich das http-Modul, und gibt die Anzahl der Parameter des aktuellen Moduls an, die größer oder gleich 2 sein muss NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE, //Gibt die Methode ngx_http_file_cache_set_slot an, auf die die Methode set() zeigt, NGX_HTTP_MAIN_CONF_OFFSET, Offset von (ngx_http_proxy_main_conf_t, Caches), &ngx_http_proxy_module } } Wie Sie sehen, ist die von dieser Anweisung verwendete Analysemethode ngx_http_file_cache_set_slot(). Hier lesen wir direkt den Quellcode dieser Methode: char *ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *confp = conf; off_t max_größe; u_char *letzter, *p; Zeit_t inaktiv; ssize_t Größe; ngx_str_t s, Name, *Wert; ngx_int_t Loader-Dateien, Manager-Dateien; ngx_msec_t loader_sleep, manager_sleep, loader_threshold, Managerschwelle; ngx_uint_t i, n, temporärer_Pfad verwenden; ngx_array_t *Caches; ngx_http_file_cache_t *Cache, **ce; Cache = ngx_pcalloc(cf->pool, Größe von(ngx_http_file_cache_t)); wenn (Cache == NULL) { gib NGX_CONF_ERROR zurück; } cache->Pfad = ngx_pcalloc(cf->pool, sizeof(ngx_path_t)); if (cache->pfad == NULL) { gib NGX_CONF_ERROR zurück; } // Initialisiere die Standardwerte jedes Attributs use_temp_path = 1; inaktiv = 600; loader_files = 100; loader_sleep = 50; loader_threshold = 200; manager_dateien = 100; manager_sleep = 50; Managerschwelle = 200; Name.Länge = 0; Größe = 0; max_Größe = NGX_MAX_OFF_T_VALUE; // Beispielkonfiguration: proxy_cache_path /Benutzer/Mike/nginx-cache levels=1:2 keys_zone=one:10m max_size=10g inactive=60m use_temp_path=off; // Hier speichert cf->args->elts die Token-Elemente, die beim Parsen in der Anweisung proxy_cache_path enthalten sind. // Das sogenannte Token-Element bezieht sich auf die durch Leerzeichen getrennten Zeichenfragmente value = cf->args->elts; // value[1] ist der erste Parameter der Konfiguration. Dies ist der Stammpfad, in dem die Cache-Datei gespeichert wird cache->path->name = value[1]; wenn (Cache->Pfad->Name.Daten[Cache->Pfad->Name.Länge - 1] == '/') { Cache->Pfad->Name.Länge--; } wenn (ngx_conf_full_name(cf->cycle, &cache->path->name, 0) != NGX_OK) { gib NGX_CONF_ERROR zurück; } // Beginnen Sie mit der Analyse ab dem dritten Parameter for (i = 2; i < cf->args->nelts; i++) { // Wenn der dritte Parameter mit „levels=“ beginnt, analysiere den Unterparameter „levels“, wenn (ngx_strncmp(value[i].data, „levels=“, 7) == 0) { p = value[i].data + 7; // Aktuelle Position berechnen, um mit der Analyse zu beginnen last = value[i].data + value[i].len; // Position des letzten Zeichens berechnen // Mit der Analyse beginnen 1:2 für (n = 0; n < NGX_MAX_PATH_LEVEL und p < letztes; n++) { wenn (*p > '0' und *p < '3') { // Holen Sie sich den aktuellen Parameterwert, z. B. 1 und 2, die analysiert werden müssen Cache->Pfad->Ebene[n] = *p++ - '0'; Cache->Pfad->Länge += Cache->Pfad->Ebene[n] + 1; wenn (p == letzte) { brechen; } // Wenn das aktuelle Zeichen ein Doppelpunkt ist, fahren Sie mit der Analyse des nächsten Zeichens fort. // Der NGX_MAX_PATH_LEVEL-Wert ist hier 3, was bedeutet, dass es höchstens 3 Unterverzeichnisse nach dem Ebenenparameter gibt, wenn (*p++ == ':' && n < NGX_MAX_PATH_LEVEL - 1 && p < last) { weitermachen; } gehe zu ungültigen Ebenen; } gehe zu ungültigen Ebenen; } wenn (Cache->Pfad->Länge < 10 + NGX_MAX_PATH_LEVEL) { weitermachen; } ungültige_Ebenen: ngx_conf_log_error(NGX_LOG_EMERG, vgl. 0, "ungültige \"Ebenen\" \"%V\"", &value[i]); gib NGX_CONF_ERROR zurück; } // Wenn der aktuelle Parameter mit „use_temp_path=“ beginnt, analysieren Sie den Parameter use_temp_path, der ein- oder ausgeschaltet sein kann. // Gibt an, ob die aktuelle Cache-Datei zuerst in einem temporären Ordner gespeichert und dann in den Zielordner geschrieben wird. Wenn es deaktiviert ist, wird es direkt im Zielordner gespeichert, wenn (ngx_strncmp (value [i] .data, "use_temp_path =", 14) == 0) { // Wenn aktiviert, markiere use_temp_path als 1 wenn (ngx_strcmp(&value[i].data[14], "on") == 0) { use_temp_path = 1; // Wenn es ausgeschaltet ist, markiere use_temp_path als 0 } sonst wenn (ngx_strcmp(&value[i].data[14], "off") == 0) { use_temp_path = 0; // Wenn es mehr als 100 sind, gib eine Analyseausnahme zurück} else { ngx_conf_log_error(NGX_LOG_EMERG, vgl. 0, "ungültiger use_temp_path-Wert \"%V\", " "es muss \"an\" oder \"aus\" sein", &Wert[i]); gib NGX_CONF_ERROR zurück; } weitermachen; } // Wenn der Parameter mit „keys_zone=“ beginnt, analysieren Sie den Parameter keys_zone. Das Format dieses Parameters ist keys_zone=one:10m. // Hier ist 1 ein Name für die nachfolgende Standortkonfiguration und 10 m ist eine Größe. // Gibt die Cachegröße zum Speichern von Schlüsseln an, wenn (ngx_strncmp(value[i].data, "keys_zone=", 10) == 0) { Name.Daten = Wert[i].Daten + 10; p = (u_char *) ngx_strchr(name.data, ':'); wenn (p) { // Berechnen Sie die Länge des Namens, der den Namen des aktuellen Puffers aufzeichnet, also einen hier name.länge = p - name.daten; p++; // Analysiere die angegebene Größe s.len = value[i].data + value[i].len - p; s.Daten = p; // Analysiere die Größe und konvertiere die angegebene Größe in Bytes. Die Anzahl der Bytes muss hier größer als 8191 sein Größe = ngx_parse_size(&s); wenn (Größe > 8191) { weitermachen; } } ngx_conf_log_error(NGX_LOG_EMERG, vgl. 0, "ungültige Schlüsselzonengröße \"%V\"", &value[i]); gib NGX_CONF_ERROR zurück; } // Wenn der Parameter mit „inactive=“ beginnt, analysieren Sie den inaktiven Parameter. Das Parameterformat ist beispielsweise inaktiv=60m, // Gibt an, wie lange die zwischengespeicherte Datei abläuft, nachdem nicht darauf zugegriffen wurde, if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) { s.len = Wert[i].len - 9; s.Daten = Wert[i].Daten + 9; // Zeit analysieren und in Zeitdauer in Sekunden umwandeln inactive = ngx_parse_time(&s, 1); wenn (inaktiv == (Zeit_t) NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, vgl. 0, "ungültiger inaktiver Wert \"%V\"", &value[i]); gib NGX_CONF_ERROR zurück; } weitermachen; } // Wenn der Parameter mit „max_size=“ beginnt, analysieren Sie den max_size-Parameter. Das Parameterformat ist beispielsweise max_size=10g, // Gibt den maximalen Speicherplatz an, den der aktuelle Cache verwenden kann, wenn (ngx_strncmp(value[i].data, "max_size=", 9) == 0) { s.len = Wert[i].len - 9; s.Daten = Wert[i].Daten + 9; // Den analysierten Wert in die Anzahl der Bytes umwandeln max_size = ngx_parse_offset(&s); wenn (max_size < 0) { ngx_conf_log_error(NGX_LOG_EMERG, vgl. 0, "ungültiger max_size-Wert \"%V\"", &value[i]); gib NGX_CONF_ERROR zurück; } weitermachen; } // Wenn der Parameter mit „loader_files=“ beginnt, analysieren Sie den loader_files-Parameter. Der Parameter hat die Form loader_files=100. // Gibt an wie viele Dateien im Cache-Verzeichnis beim Starten von nginx standardmäßig in den Cache geladen werden if (ngx_strncmp(value[i].data, "loader_files=", 13) == 0) { // Analysiere den Wert des Parameters loader_files loader_files = ngx_atoi(value[i].data + 13, value[i].len - 13); wenn (loader_files == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, vgl. 0, "ungültiger loader_files-Wert \"%V\"", &value[i]); gib NGX_CONF_ERROR zurück; } weitermachen; } // Wenn der Parameter mit „loader_sleep=“ beginnt, analysieren Sie den loader_sleep-Parameter. Der Parameter hat die Form loader_sleep=10s. // Gibt an, wie lange nach dem Laden jeder Datei geruht werden soll, bevor die nächste Datei geladen wird, if (ngx_strncmp(value[i].data, "loader_sleep=", 13) == 0) { s.len = Wert[i].len - 13; s.Daten = Wert[i].Daten + 13; // Konvertieren Sie den Wert von loader_sleep, hier in Millisekunden loader_sleep = ngx_parse_time(&s, 0); wenn (loader_sleep == (ngx_msec_t)NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, vgl. 0, "ungültiger loader_sleep-Wert \"%V\"", &value[i]); gib NGX_CONF_ERROR zurück; } weitermachen; } // Wenn der Parameter mit „loader_threshold=“ beginnt, analysieren Sie den loader_threshold-Parameter, der die Form loader_threshold=10s hat. // Gibt die maximale Zeit an, die zum Laden einer Datei verwendet werden kann, wenn (ngx_strncmp(value[i].data, "loader_threshold=", 17) == 0) { s.len = Wert[i].len - 17; s.Daten = Wert[i].Daten + 17; // Den Wert von loader_threshold analysieren und in Millisekunden konvertieren loader_threshold = ngx_parse_time(&s, 0); wenn (loader_threshold == (ngx_msec_t)NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, vgl. 0, "ungültiger loader_threshold-Wert \"%V\"", &value[i]); gib NGX_CONF_ERROR zurück; } weitermachen; } // Wenn der Parameter mit „manager_files=“ beginnt, analysieren Sie den Parameter „manager_files“, der die Form „manager_files=100“ hat. // Gibt an, dass die Dateien mit dem LRU-Algorithmus gelöscht werden, wenn der Cache-Speicherplatz erschöpft ist. Bei jeder Iteration werden jedoch höchstens die in manager_files angegebene Anzahl von Dateien gelöscht, wenn (ngx_strncmp(value[i].data, "manager_files=", 14) == 0) { // Den Wert des Parameters manager_files analysieren manager_files = ngx_atoi(value[i].data + 14, value[i].len - 14); wenn (manager_files == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, vgl. 0, "ungültiger manager_files-Wert \"%V\"", &value[i]); gib NGX_CONF_ERROR zurück; } weitermachen; } // Wenn der Parameter mit „manager_sleep=“ beginnt, analysieren Sie den Parameter „manager_sleep“, der die Form „manager_sleep=1s“ hat. // Gibt an, dass jede Iteration für die durch den Parameter manager_sleep angegebene Dauer pausiert, wenn (ngx_strncmp(value[i].data, "manager_sleep=", 14) == 0) { s.len = Wert[i].len - 14; s.Daten = Wert[i].Daten + 14; // Den durch manager_sleep angegebenen Wert analysieren manager_sleep = ngx_parse_time(&s, 0); wenn (manager_sleep == (ngx_msec_t) NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, vgl. 0, "ungültiger manager_sleep-Wert \"%V\"", &value[i]); gib NGX_CONF_ERROR zurück; } weitermachen; } // Wenn der Parameter mit „manager_threshold=“ beginnt, wird der Parameter manager_threshold analysiert. Der Parameter hat die Form manager_threshold=2s. // Gibt an, dass die längste Zeit für jede Iteration zum Löschen von Dateien den durch diesen Parameter angegebenen Wert nicht überschreiten kann, wenn (ngx_strncmp(value[i].data, "manager_threshold=", 18) == 0) { s.len = Wert[i].len - 18; s.Daten = Wert[i].Daten + 18; // Den Wert des Parameters „manager_threshold“ analysieren und in einen Wert in Millisekunden umwandeln manager_threshold = ngx_parse_time(&s, 0); wenn (manager_threshold == (ngx_msec_t)NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, vgl. 0, "ungültiger Manager_Threshold-Wert \"%V\"", &value[i]); gib NGX_CONF_ERROR zurück; } weitermachen; } ngx_conf_log_error(NGX_LOG_EMERG, vgl. 0, "ungültiger Parameter \"%V\"", &value[i]); gib NGX_CONF_ERROR zurück; } wenn (name.länge == 0 || größe == 0) { ngx_conf_log_error(NGX_LOG_EMERG, vgl. 0, "\"%V\" muss den Parameter \"keys_zone\" haben", &Befehl->Name); gib NGX_CONF_ERROR zurück; } // Die Werte von cache->path->manager und cache->path->loader sind hier zwei Funktionen. Es ist zu beachten, dass // Nachdem nginx gestartet wurde, werden zwei separate Prozesse gestartet, ein Cache-Manager und ein Cache-Loader. // Führt die unter cache->path->manager angegebene Methode für jeden gemeinsam genutzten Speicher in einer Schleife kontinuierlich aus. // Um den Cache zu leeren. Der andere Prozess, der Cache Loader, wird nur einmal 60 Sekunden nach dem Start von nginx ausgeführt. // Die Ausführungsmethode ist die durch cache->path->loader angegebene Methode. // Die Hauptfunktion dieser Methode besteht darin, vorhandene Dateidaten in den aktuellen gemeinsam genutzten Speicher zu laden cache->path->manager = ngx_http_file_cache_manager; Cache->Pfad->Lader = ngx_http_file_cache_loader; Cache->Pfad->Daten = Cache; Cache->Pfad->Conf_File = cf->Conf_File->Dateiname.Daten; Cache->Pfad->Zeile = cf->Conf_File->Zeile; cache->loader_files = loader_files; cache->loader_sleep = loader_sleep; cache->loader_threshold = loader_threshold; cache->manager_dateien = manager_dateien; cache->manager_sleep = manager_sleep; cache->manager_schwelle = manager_schwelle; // Füge den aktuellen Pfad zum Zyklus hinzu. Diese Pfade werden später überprüft. Wenn der Pfad nicht existiert, wird der entsprechende Pfad erstellt, wenn (ngx_add_path(cf, &cache->path) != NGX_OK) { gib NGX_CONF_ERROR zurück; } // Fügen Sie den aktuellen gemeinsam genutzten Speicher zur Liste der gemeinsam genutzten Speicher hinzu, die durch cf->cycle->shared_memory cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post); angegeben ist. wenn (cache->shm_zone == NULL) { gib NGX_CONF_ERROR zurück; } wenn (Cache->SHM_Zone->Daten) { ngx_conf_log_error(NGX_LOG_EMERG, vgl. 0, "Duplikatzone \"%V\"", &name); gib NGX_CONF_ERROR zurück; } // Dies gibt die Initialisierungsmethode für jeden gemeinsam genutzten Speicher an, die ausgeführt wird, wenn der Masterprozess gestartet wird cache->shm_zone->init = ngx_http_file_cache_init; Cache->Shm_Zone->Daten = Cache; cache->use_temp_path = use_temp_path; cache->inactive = inaktiv; cache->max_size = max_size; Caches = (ngx_array_t *) (confp + cmd->offset); ce = ngx_array_push(Caches); wenn (ce == NULL) { gib NGX_CONF_ERROR zurück; } *ce = Cache; gib NGX_CONF_OK zurück; } Wie aus dem obigen Code ersichtlich ist, wird in der Methode proxy_cache_path hauptsächlich eine ngx_http_file_cache_t-Struktur initialisiert. Die verschiedenen Eigenschaften in dieser Struktur werden durch Analysieren der verschiedenen Parameter von proxy_cache_path erhalten. 3.2 Starten des Cache-Manager- und Cache-Loader-Prozesses Die Einstiegsmethode des nginx-Programms ist die main()-Methode von nginx.c. Wenn der Master-Worker-Prozessmodus aktiviert ist, wird schließlich die Methode ngx_master_process_cycle() aufgerufen, die zuerst den Worker-Prozess startet, um Client-Anforderungen zu empfangen; dann werden die Cache-Manager- und Cache-Loader-Prozesse gestartet; schließlich wird eine Endlosschleife gestartet, um die vom Benutzer in der Befehlszeile an nginx gesendeten Anweisungen zu verarbeiten. Nachfolgend sehen Sie den Quellcode zum Starten der Cache-Manager- und Cache-Loader-Prozesse: Leere ngx_master_process_cycle(ngx_cycle_t *Zyklus) { ... // Holen Sie sich die Kernmodulkonfiguration ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); // Starten Sie jeden Arbeitsprozess ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); // Cache-Prozess starten ngx_start_cache_manager_processes(cycle, 0); ... } Was den Start von Cache-Manager- und Cache-Loader-Prozessen betrifft, ist ersichtlich, dass dies hauptsächlich in der Methode ngx_start_cache_manager_processes () geschieht. Das Folgende ist der Quellcode dieser Methode: statischer void ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn) { ngx_uint_t i, Manager, Lader; ngx_path_t **Pfad; ngx_channel_t ch; Manager = 0; Lader = 0; Pfad = ngx_cycle->paths.elts; für (i = 0; i < ngx_cycle->paths.nelts; i++) { //Überprüfen Sie, ob ein Pfad den Manager als 1 angibt. if (Pfad[i]->Manager) { Manager = 1; } //Überprüfen Sie, ob ein Pfad den Loader als 1 angibt. if (Pfad[i]->Loader) { Lader = 1; } } // Wenn kein Pfadmanager als 1 angegeben ist, direkt zurückgeben, wenn (manager == 0) { zurückkehren; } // Erstellen Sie einen Prozess, um den in der Methode ngx_cache_manager_process_cycle() ausgeführten Zyklus auszuführen. Beachten Sie, dass // Beim Rückruf der Methode ngx_cache_manager_process_cycle ist der zweite hier übergebene Parameter ngx_cache_manager_ctx ngx_spawn_process(Zyklus, ngx_cache_manager_process_cycle, &ngx_cache_manager_ctx, "Cache-Manager-Prozess", Wiederauferstehung? NGX_PROCESS_JUST_RESPAWN: NGX_PROCESS_RESPAWN); ngx_memzero(&ch, Größe von(ngx_channel_t)); // Erstellen Sie eine ch-Struktur, um die Erstellungsnachricht des aktuellen Prozesses zu senden. ch.command = NGX_CMD_OPEN_CHANNEL; ch.pid = ngx_processes[ngx_process_slot].pid; ch.slot = ngx_process_slot; ch.fd = ngx_processes[ngx_process_slot].Kanal[0]; // Senden Sie die Nachricht, dass der Cache-Manager-Prozess erstellt wurde ngx_pass_open_channel(cycle, &ch); wenn (Lader == 0) { zurückkehren; } // Erstellen Sie einen Prozess, um den von ngx_cache_manager_process_cycle() angegebenen Prozess auszuführen. Es ist zu beachten, dass // Beim Rückruf der Methode ngx_cache_manager_process_cycle ist der zweite hier übergebene Parameter ngx_cache_loader_ctx ngx_spawn_process(Zyklus, ngx_cache_manager_process_cycle, &ngx_cache_loader_ctx, "Cache-Loader-Prozess", Wiederauferstehung? NGX_PROCESS_JUST_SPAWN: NGX_PROCESS_NORESPAWN); // Erstellen Sie eine ch-Struktur, um die Erstellungsnachricht des aktuellen Prozesses zu senden. ch.command = NGX_CMD_OPEN_CHANNEL; ch.pid = ngx_processes[ngx_process_slot].pid; ch.slot = ngx_process_slot; ch.fd = ngx_processes[ngx_process_slot].Kanal[0]; // Senden Sie die Nachricht, dass der Cache-Loader-Prozess erstellt wurde ngx_pass_open_channel(cycle, &ch); } Der obige Code ist eigentlich ganz einfach. Zunächst wird geprüft, ob ein Pfad die Verwendung von Cache-Manager oder Cache-Loader angibt. Wenn ja, wird die entsprechende Vererbung gestartet. Andernfalls werden die Prozesse Cache-Manager und Cache-Loader nicht erstellt. Zum Starten dieser beiden Prozesse werden die folgenden Methoden verwendet: // Starten Sie den Cache-Manager-Prozess ngx_spawn_process(cycle, ngx_cache_manager_process_cycle, &ngx_cache_manager_ctx, "Cache-Manager-Prozess", Wiederauferstehung? NGX_PROCESS_JUST_RESPAWN: NGX_PROCESS_RESPAWN); // Starten Sie den Cache-Loader-Prozess ngx_spawn_process(cycle, ngx_cache_manager_process_cycle, &ngx_cache_loader_ctx, "Cache-Loader-Prozess", Wiederauferstehung? NGX_PROCESS_JUST_SPAWN: NGX_PROCESS_NORESPAWN); Die Hauptfunktion der Methode ngx_spawn_process () besteht hier darin, einen neuen Prozess zu erstellen. Nachdem der Prozess erstellt wurde, wird die durch den zweiten Parameter angegebene Methode ausgeführt, und der bei der Ausführung der Methode übergebene Parameter ist das hier durch den dritten Parameter angegebene Strukturobjekt. Beachten Sie die beiden Möglichkeiten, den oben beschriebenen Prozess zu starten. Die Methode, die nach dem Erstellen des neuen Prozesses ausgeführt wird, ist ngx_cache_manager_process_cycle(), aber die beim Aufruf dieser Methode übergebenen Parameter sind unterschiedlich, einer ist ngx_cache_manager_ctx und der andere ist ngx_cache_loader_ctx. Hier schauen wir uns zunächst die Definitionen dieser beiden Strukturen an: // Der ngx_cache_manager_process_handler gibt hier die Methode an, die der aktuelle Cache-Manager-Prozess ausführen wird. // Cache-Manager-Prozess gibt den Namen des Prozesses an, und die letzte 0 gibt an, wie lange der aktuelle Prozess nach dem Start ausgeführt wird. // Die Methode ngx_cache_manager_process_handler() wird hier sofort ausgeführt static ngx_cache_manager_ctx_t ngx_cache_manager_ctx = { ngx_cache_manager_process_handler, "Cache-Manager-Prozess", 0 }; // Der ngx_cache_loader_process_handler gibt hier die Methode an, die der aktuelle Cache Loader-Prozess ausführen wird. // Die Methode ngx_cache_loader_process_handler() wird 60 Sekunden nach dem Start des Cache-Loader-Prozesses ausgeführt static ngx_cache_manager_ctx_t ngx_cache_loader_ctx = { ngx_cache_loader_process_handler, "Cache-Loader-Prozess", 60000 }; Wie Sie sehen, definieren diese beiden Strukturen hauptsächlich die unterschiedlichen Verhaltensweisen der Cache-Manager- und Cache-Loader-Prozesse. Sehen wir uns an, wie die Methode ngx_cache_manager_process_cycle() diese beiden Methoden aufruft: statischer void ngx_cache_manager_process_cycle(ngx_cycle_t *Zyklus, void *Daten) { ngx_cache_manager_ctx_t *ctx = Daten; ungültig *ident[4]; ngx_event_t ev; ngx_process = NGX_PROCESS_HELPER; // Der aktuelle Prozess wird hauptsächlich für die Arbeit des Cache-Managers und des Cache-Loaders verwendet, sodass er nicht auf den Socket hören muss und daher hier geschlossen werden muss ngx_close_listening_sockets(cycle); /* Legen Sie eine moderate Anzahl von Verbindungen für einen Hilfsprozess fest. */ Zyklus->Verbindung_n = 512; // Initialisiere den aktuellen Prozess, indem du hauptsächlich einige Parameterattribute festlegst und schließlich das Ereignis des Abhörens des Kanal-Handles[1] für den aktuellen Prozess festlegst, um die Nachricht des Masterprozesses zu empfangen ngx_worker_process_init(cycle, -1); ngx_memzero(&ev, Größe von(ngx_event_t)); // Für den Cache-Manager bezieht sich der Handler hier auf die Methode ngx_cache_manager_process_handler(). // Für den Cache-Loader zeigt der Handler hier auf die Methode ngx_cache_loader_process_handler() ev.handler = ctx->handler; ev.Daten = ident; ev.log = Zyklus->Protokoll; ident[3] = (void *) -1; // Das Cache-Modul muss keine gemeinsame Sperre verwenden ngx_use_accept_mutex = 0; ngx_setproctitle(ctx->name); // Das aktuelle Ereignis zur Ereigniswarteschlange hinzufügen. Die Verzögerungszeit des Ereignisses ist ctx->delay. Für den Cache-Manager ist dieser Wert 0. // Für den Cache-Loader beträgt der Wert 60 s. // Es ist zu beachten, dass in der aktuellen Ereignisverarbeitungsmethode, wenn ngx_cache_manager_process_handler() das aktuelle Ereignis verarbeitet hat, // Das aktuelle Ereignis wird erneut zur Ereigniswarteschlange hinzugefügt, wodurch die Funktion der zeitgesteuerten Verarbeitung realisiert wird; und für // die Methode ngx_cache_loader_process_handler() wird das aktuelle Ereignis nach einmaliger Verarbeitung nicht erneut // zur Ereigniswarteschlange hinzugefügt, was also gleichbedeutend damit ist, dass das aktuelle Ereignis nur einmal ausgeführt wird und dann der Cache-Loader-Prozess beendet wird ngx_add_timer(&ev, ctx->delay); für ( ;; ) { // Wenn der Master den aktuellen Prozess als beendet oder beendet markiert, beenden Sie den Prozess, wenn (ngx_terminate || ngx_quit) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "wird beendet"); Ausfahrt (0); } // Wenn der Masterprozess eine Reopen-Nachricht sendet, öffne alle Cache-Dateien erneut, wenn (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "Protokolle erneut öffnen"); ngx_reopen_files(Zyklus, -1); } //Ereignisse in der Ereigniswarteschlange ausführen ngx_process_events_and_timers(cycle); } } Im obigen Code wird zuerst ein Ereignisobjekt erstellt, ev.handler = ctx->handler; die vom Ereignis zu verarbeitende Logik wird angegeben, d. h. die Methode, die dem ersten Parameter in den beiden obigen Strukturen entspricht; dann wird das Ereignis zur Ereigniswarteschlange hinzugefügt, d. h. ngx_add_timer(&ev, ctx->delay);, es ist zu beachten, dass der zweite Parameter hier der dritte Parameter ist, der in den beiden obigen Strukturen angegeben ist, d. h. die Ausführungszeit der handler()-Methode wird durch die Verzögerungszeit des Ereignisses gesteuert; schließlich wird in einer unendlichen for-Schleife die Methode ngx_process_events_and_timers() verwendet, um die Ereignisse in der Ereigniswarteschlange kontinuierlich zu überprüfen und die Ereignisse zu verarbeiten. 3.3 Verarbeitungslogik des Cache-Manager-Prozesses Was den Cache-Manager-Verarbeitungsprozess betrifft, so geht aus der obigen Erklärung hervor, dass er in der Methode ngx_cache_manager_process_handler() in der von ihr definierten Cache-Manager-Struktur ausgeführt wird. Nachfolgend sehen Sie den Quellcode dieser Methode: statischer void ngx_cache_manager_process_handler(ngx_event_t *ev) { ngx_uint_t ich; ngx_msec_t nächstes, n; ngx_path_t **Pfad; nächstes = 60 * 60 * 1000; Pfad = ngx_cycle->paths.elts; für (i = 0; i < ngx_cycle->paths.nelts; i++) { // Die Manager-Methode bezieht sich hier auf die Methode ngx_http_file_cache_manager() if (path[i]->manager) { n = Pfad[i]->Manager(Pfad[i]->Daten); nächstes = (n <= nächstes)? n: nächstes; ngx_time_update(); } } wenn (nächstes == 0) { nächster = 1; } // Nachdem eine Verarbeitung abgeschlossen ist, wird das aktuelle Ereignis für die nächste Verarbeitung erneut zur Ereigniswarteschlange hinzugefügt ngx_add_timer(ev, next); } Dabei werden zunächst alle Pfaddefinitionen eingeholt und anschließend deren manager()-Methoden auf Leerheit geprüft. Ist dies nicht der Fall, wird die Methode aufgerufen. Die tatsächliche Methode, auf die die Methode manager() hier zeigt, ist diejenige, die beim Parsen der Direktive proxy_cache_path in Abschnitt 3.1 definiert ist, also cache->path->manager = ngx_http_file_cache_manager;, was bedeutet, dass diese Methode die Hauptmethode zum Verwalten des Caches ist. Nach dem Aufruf der Verwaltungsmethode wird das aktuelle Ereignis für den nächsten Cache-Verwaltungszyklus zur Ereigniswarteschlange hinzugefügt. Nachfolgend sehen Sie den Quellcode der Methode ngx_http_file_cache_manager(): statisch ngx_msec_t ngx_http_file_cache_manager(void *data) { // Die ngx_http_file_cache_t-Struktur wird hier durch Analysieren des Proxy_Cache_Path-Konfigurationselements ngx_http_file_cache_t *cache = data; erhalten. off_t Größe; Zeit_t warte; ngx_msec_t verstrichen, weiter; ngx_uint_t Anzahl, Wasserzeichen; Cache->letzter = ngx_current_msec; Cache->Dateien = 0; // Die Methode ngx_http_file_cache_expire() befindet sich hier in einer Endlosschleife und prüft ständig, ob am Ende der Cache-Warteschlange abgelaufener // gemeinsam genutzter Speicher vorhanden ist. Wenn dies der Fall ist, werden dieser und die entsprechende Datei gelöscht. next = (ngx_msec_t) ngx_http_file_cache_expire(cache) * 1000; // next ist der Rückgabewert der Methode ngx_http_file_cache_expire(), die nur in zwei Fällen 0 zurückgibt: // 1. Wenn die Anzahl der gelöschten Dateien die von manager_files angegebene Anzahl von Dateien überschreitet; // 2. Wenn die Gesamtzeit zum Löschen jeder Datei die durch manager_threshold angegebene Gesamtzeit überschreitet; // Wenn next 0 ist, bedeutet dies, dass ein Stapel Cache-Bereinigungsarbeiten abgeschlossen wurde. Zu diesem Zeitpunkt ist es erforderlich, vor der nächsten Bereinigungsarbeit eine Weile zu schlafen. // Die Dauer dieses Ruhezustands entspricht dem durch manager_sleep angegebenen Wert. Das heißt, der Wert von next ist hier tatsächlich die Wartezeit für die nächste // Cache-Bereinigung, wenn (next == 0) { weiter = Cache->Manager_Sleep; gehe zu fertig; } für ( ;; ) { ngx_shmtx_lock(&cache->shpool->mutex); // Größe bezieht sich hier auf die Gesamtgröße, die vom aktuellen Cache verwendet wird // Anzahl gibt die Anzahl der Dateien im aktuellen Cache an // Wasserzeichen gibt den Wasserstand an, der 7/8 der Gesamtzahl der Dateien beträgt, die gespeichert werden können Größe = Cache->sh->Größe; Anzahl = Cache->sh->Anzahl; Wasserzeichen = Cache->sh->Wasserzeichen; ngx_shmtx_unlock(&cache->shpool->mutex); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "Größe des HTTP-Dateicaches: %O c:%ui w:%i", Größe, Anzahl, (ngx_int_t) Wasserzeichen); // Wenn die vom aktuellen Cache verwendete Speichergröße kleiner ist als die maximal nutzbare Größe und die Anzahl der zwischengespeicherten Dateien kleiner als das Wasserzeichen ist, // Gibt an, dass Cache-Dateien weiterhin gespeichert werden können. Anschließend wird die Schleife verlassen, wenn (Größe < Cache->max_size und Anzahl < Wasserzeichen) { brechen; } // Hierher zu gehen bedeutet, dass die verfügbaren gemeinsam genutzten Speicherressourcen nicht ausreichen // Hier geht es hauptsächlich darum, das Löschen nicht referenzierter Dateien in der aktuellen Warteschlange zu erzwingen, unabhängig davon, ob sie abgelaufen sind wait = ngx_http_file_cache_forced_expire(cache); // Berechne die nächste Ausführungszeit, wenn (wait > 0) { nächstes = (ngx_msec_t) warten * 1000; brechen; } // Wenn das aktuelle Nginx beendet wurde oder beendet wurde, aus der Schleife springen, if (ngx_quit || ngx_terminate) { brechen; } // Wenn die Anzahl der aktuell gelöschten Dateien die von manager_files angegebene Anzahl überschreitet, beenden Sie die Schleife. // Und geben Sie die gewünschte Ruhezeit vor der nächsten Bereinigung an, wenn (++cache->files >= cache->manager_files) { weiter = Cache->Manager_Sleep; brechen; } ngx_time_update(); verstrichen = ngx_abs((ngx_msec_int_t) (ngx_current_msec - Cache->letzter)); // Wenn der aktuelle Löschvorgang länger dauert als die durch manager_threshold angegebene Zeit, dann verlassen Sie die Schleife. // Und geben Sie die erforderliche Ruhezeit vor der nächsten Bereinigung an, wenn (verstrichen >= Cache->Manager_Threshold) { weiter = Cache->Manager_Sleep; brechen; } } Erledigt: verstrichen = ngx_abs((ngx_msec_int_t) (ngx_current_msec - Cache->letzter)); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "HTTP-Datei-Cache-Manager: %ui e:%M n:%M", Cache->Dateien, abgelaufen, weiter); als nächstes zurückkehren; } In der Methode ngx_http_file_cache_manager() wird zuerst die Methode ngx_http_file_cache_expire() aufgerufen. Die Hauptfunktion dieser Methode besteht darin, zu prüfen, ob das Element am Ende der aktuellen gemeinsam genutzten Speicherwarteschlange abgelaufen ist. Wenn es abgelaufen ist, wird anhand der Anzahl der Referenzen und der Frage, ob das Element gelöscht werden soll, bestimmt, ob das Element und die dem Element entsprechende Datenträgerdatei gelöscht werden müssen. Nach dieser Prüfung wird eine unendliche For-Schleife gestartet. Der Hauptzweck der Schleife besteht darin, zu prüfen, ob die aktuell gemeinsam genutzten Speicherressourcen knapp sind, d. h. ob der verwendete Speicher den durch max_size definierten maximalen Speicher überschreitet oder ob die Gesamtzahl der aktuell zwischengespeicherten Dateien 7/8 der Gesamtzahl der Dateien überschreitet. Wenn eine dieser beiden Bedingungen erfüllt ist, wird der Versuch unternommen, die Cache-Datei zwangs zu löschen. Hier haben wir zuerst die Methode ngx_http_file_cache_expire () gelesen: static time_t ngx_http_file_cache_expire (ngx_http_file_cache_t *cache) { u_char *Name, *p; Größe_t Länge; time_t jetzt, warte; ngx_path_t *path; ngx_msec_t verstrichen; ngx_queue_t *q; ngx_http_file_cache_node_t *fcn; u_char Key [2 * ngx_http_cache_key_len]; ngx_log_debug0 (ngx_log_debug_http, ngx_cycle-> log, 0,, "HTTP -Datei -Cache verfällt"); path = cache-> path; len = path-> name.len + 1 + path-> len + 2 * ngx_http_cache_key_len; name = ngx_alloc (len + 1, ngx_cycle-> log); if (name == null) { Rückgabe 10; } ngx_memcpy (name, path-> name.data, path-> name.len); jetzt = ngx_time (); ngx_shmtx_lock (& cache-> shpool-> mutex); für ( ;; ) { // Wenn der aktuelle nginx beendet oder beendet ist, springen Sie aus der aktuellen Schleife, wenn (ngx_quit || ngx_terminate) { warte = 1; brechen; } // Wenn die aktuelle gemeinsame Speicherwarteschlange leer ist, springen Sie aus der aktuellen Schleife, wenn (ngx_queue_empty (& cache-> sh-> queue)) { warte = 10; brechen; } // Erhalten Sie das letzte Element der Warteschlange q = ngx_queue_last (& cache-> sh-> queue); // Erhalten Sie den Warteschlangenknoten fcn = ngx_queue_data (q, ngx_http_file_cache_node_t, queue); // Berechnen Sie die Zeitdauer zwischen der Ablaufzeit des Knotens und der aktuellen Zeitwartung = fcn-> Ablauf - jetzt; // Wenn der aktuelle Knoten nicht abgelaufen ist, beenden Sie die aktuelle Schleife, wenn (warten> 0) { Warten Sie = warten> 10? 10: Warten Sie; brechen; } ngx_log_debug6 (ngx_log_debug_http, ngx_cycle-> log, 0,, "HTTP -Datei -Cache verfallen: #%d%d%02XD%02XD%02XD%02XD", fcn-> count, fcn-> existiert, fcn-> key [0], fcn-> key [1], fcn-> key [2], fcn-> key [3]); // Die Anzahl der hier zeigt die Anzahl der aktuellen Knoten an. // Die Hauptaktion hier besteht darin, den aktuellen Knoten aus der Warteschlange zu entfernen und die Datei zu löschen, die dem Knoten ngx_http_file_cache_delete (cache, q, name) entspricht. gehe zum nächsten; } // Wenn der aktuelle Knoten gelöscht wird, muss der aktuelle Prozess ihn nicht verarbeiten, wenn (fcn-> löschen) { warte = 1; brechen; } // Hier geht es um, dass der aktuelle Knoten abgelaufen ist, aber die Referenzzahl größer als 0 ist, und kein Prozess löscht den Knoten // Der Name der Datei nach der HEX-Berechnung des Knotens wird hier berechnet. len = ngx_http_cache_key_len - sizeof (ngx_rbtree_key_t); (void) ngx_hex_dump (p, fcn-> key, len); // Da der aktuelle Knoten rechtzeitig abgelaufen ist, es jedoch Anfragen auf den Knoten verweisen, und kein Prozess löscht den Knoten. // Dies bedeutet, dass der Knoten beibehalten werden sollte. Daher versuchen wir, den Knoten am Ende der Warteschlange zu löschen und die nächste Ablaufzeit dafür neu zu berechnen. // dann in den Warteschlangenkopf ngx_queue_remove (q) einfügen; fcn-> expire = ngx_time () + cache-> inaktiv; ngx_queue_insert_head (& cache-> sh-> queue & fcn-> queue); ngx_log_error (ngx_log_alert, ngx_cycle-> log, 0,, "Ignorieren Sie lang gesperrte inaktive Cache -Eintrag %*s, zählen Sie: %d", (size_t) 2 * ngx_http_cache_key_len, key, fcn-> count); Weiter: // Dies ist die Logik, die erst nach dem Löschen des letzten Knotens in der Warteschlange ausgeführt wird und die entsprechende Datei gelöscht wird. // Wenn der LRU -Algorithmus zum Löschen von Dateien verwendet wird, wird höchstens die Anzahl der von diesem Parameter angegebenen Dateien gelöscht. // So, wenn Cache-> Dateien größer oder gleich zu Manager_files sind, springen warte = 0; brechen; } // Aktualisieren Sie die aktuelle Nginx -Cache -Zeit ngx_time_update (); // verstrichen ist gleich der Gesamtzeit, die für die aktuelle Deletion -Aktion erfasst wurde, verblüfft = ngx_abs ((ngx_msec_int_t) (ngx_current_msec - cache-> last)); // Wenn die Gesamtzeit den von Manager_Threshold angegebenen Wert überschreitet, springen Sie aus der aktuellen Schleife, wenn (verstrichen> = cache-> Manager_Threshold) { warte = 0; brechen; } } // Die aktuelle Sperre ngx_shmtx_unlock (& cache-> shpool-> mutex) freigeben; ngx_free (name); Kehren Sie warten; } Es ist zu erkennen, dass die Hauptverarbeitungslogik hier darin besteht, das Element am Schwanz der Warteschlange zu überprüfen. Überprüfen Sie, ob das Element abgelaufen ist. Wenn die aktuelle Elementreferenzzahl nicht 0 beträgt, wird festgestellt, ob es gelöscht wird. Wenn es gelöscht wird, verarbeitet der aktuelle Prozess das Element nicht. Schauen wir uns an, wie der Cache -Manager die Entfernung von Elementen erzwingt, wenn die Ressourcen eng sind. static time_t ngx_http_file_cache_forced_expire (ngx_http_file_cache_t *cache) { u_char *Name; Größe_t Länge; time_t warte; ngx_uint_t versucht; ngx_path_t *path; ngx_queue_t *q; ngx_http_file_cache_node_t *fcn; ngx_log_debug0 (ngx_log_debug_http, ngx_cycle-> log, 0,, "HTTP -Datei -Cache erzwungen Ablauf"); path = cache-> path; len = path-> name.len + 1 + path-> len + 2 * ngx_http_cache_key_len; name = ngx_alloc (len + 1, ngx_cycle-> log); if (name == null) { Rückgabe 10; } ngx_memcpy (name, path-> name.data, path-> name.len); warte = 10; Versuche = 20; ngx_shmtx_lock (& cache-> shpool-> mutex); // Überqueren Sie jeden Knoten kontinuierlich in der Warteschlange für (q = ngx_queue_last (& cache-> sh-> queue); q! = ngx_queue_sentinel (& cache-> sh-> queue); q = ngx_queue_prev (q)) { // Die Daten des aktuellen Knotens abrufen fcn = ngx_queue_data (q, ngx_http_file_cache_node_t, queue); ngx_log_debug6 (ngx_log_debug_http, ngx_cycle-> log, 0,, "HTTP -Datei -Cache erzwungen ausfallen: #%d%d%02xd%02xd%02xd%02xd", fcn-> count, fcn-> existiert, fcn-> key [0], fcn-> key [1], fcn-> key [2], fcn-> key [3]); // Wenn die Anzahl der Verweise auf den aktuellen Knoten 0 beträgt, löschen Sie den Knoten direkt if (fcn-> count == 0) { ngx_http_file_cache_delete (cache, q, name); warte = 0; } anders { // Versuchen Sie den nächsten Knoten. weitermachen; } warte = 1; } brechen; } ngx_shmtx_unlock (& cache-> shpool-> mutex); ngx_free (name); Kehren Sie warten; } Wie Sie sehen können, ist die Verarbeitungslogik hier relativ einfach. Wenn es nicht 0 ist, überprüfen Sie das nächste Element und so weiter. Es ist hier zu beachten, dass bei Überprüfung, dass insgesamt 20 Elemente verwiesen werden, die aktuelle Schleife herausgesprungen wird. 3.4 Cache Loader -Prozessverarbeitungslogik Wie bereits erwähnt, befindet sich der Hauptverarbeitungsfluss des Cache -Loaders in der Methode ngx_cache_loader_process_handler (). static void ngx_cache_loader_process_handler (ngx_event_t *ev) { ngx_uint_t ich; ngx_path_t ** path; ngx_cycle_t *cycle; cycle = (ngx_cycle_t *) ngx_cycle; path = cycle-> paths.elts; für (i = 0; i <cycle-> paths.nelts; i ++) { if (ngx_terminate || ngx_quit) { brechen; } // Die Loader-Methode hier bezieht Pfad [i]-> Loader (Pfad [i]-> Daten); ngx_time_update (); } } // Beenden Sie den aktuellen Vorgang nach dem Laden vollständig beendet (0); } Der Hauptverarbeitungsfluss von Cache Loader und Cache -Manager ist sehr ähnlich. Hier lesen wir weiterhin den Quellcode der Methode ngx_http_file_cache_loader (): static void ngx_http_file_cache_loader (void *data) { ngx_http_file_cache_t *cache = data; ngx_tree_ctx_t baum; // Wenn das Laden abgeschlossen ist oder das Laden in Arbeit ist, kehren Sie direkt zurück, wenn (! Cache-> sh-> kalt || cache-> sh-> laden) { zurückkehren; } // Versuchen Sie zu sperren if (! Ngx_atomic_cmp_set (& cache-> sh-> laden, 0, ngx_pid) { zurückkehren; } ngx_log_debug0 (ngx_log_debug_http, ngx_cycle-> log, 0,, "HTTP -Datei -Cache Loader"); // Der Baum ist hier ein Hauptprozessobjekt für das Laden. // Kapuliert den Betrieb des Ladens eines einzelnen Dateibaums.file_handler = ngx_http_file_cache_manage_file; // Die Operation vor dem Laden eines Verzeichnisses, hauptsächlich, um zu überprüfen, ob das aktuelle Verzeichnis den Betriebsberechtigungsbaum enthält. // Operation nach dem Laden eines Verzeichnisses ist dies tatsächlich ein leerer Methodenbaum. // Dies befasst sich hauptsächlich mit speziellen Dateien, dh Dateien, die weder Dateien noch Ordner sind. Tree.data = Cache; Baum.Alloc = 0; tree.log = ngx_cycle-> log; cache-> last = ngx_current_msec; cache-> files = 0; // beginne, alle Dateien im angegebenen Verzeichnis rekursiv zu durchqueren und sie dann gemäß der oben definierten Methode zu verarbeiten, dh sie in gemeinsamen Speicher laden, wenn (ngx_walk_tree (& baum, & cache-> path-> name) == ngx_abort) {{ cache-> sh-> laden = 0; zurückkehren; } // Ladestatus markieren Cache-> sh-> Cold = 0; cache-> sh-> laden = 0; ngx_log_error (ngx_log_notice, ngx_cycle-> log, 0,, "HTTP -Datei -Cache: %v %.3fm, BSIZE: %UZ", & cache-> Pfad-> Name, ((doppelt) cache-> sh-> Größe * cache-> bsize) / (1024 * 1024),, cache-> bsize); } Während des Ladevorgangs wird das Zielladeverzeichnis zuerst in eine NGX_TREE_CTX_T -Struktur eingekapselt, und die zum Laden der Datei verwendete Methode ist dafür angegeben. Die endgültige Ladelogik wird hauptsächlich in der Methode ngx_walk_tree () durchgeführt, und der gesamte Ladevorgang wird ebenfalls rekursiv implementiert. Das Folgende ist das Implementierungsprinzip der Methode ngx_walk_tree (): ngx_int_t ngx_walk_tree (ngx_tree_ctx_t *ctx, ngx_str_t *baum) { void *data, *pre; u_char *p, *Name; Größe_t Länge; ngx_int_t rc; ngx_err_t Fehler; ngx_str_t Datei, buf; NGX_DIR_T DIR; ngx_str_null (& buf); ngx_log_debug1 (ngx_log_debug_core, ctx-> log, 0,, "Walk Tree \"%v \ "", Baum); // Öffnen Sie das Zielverzeichnis if (ngx_open_dir (Baum, & Dir) == ngx_error) { ngx_log_error (ngx_log_crit, ctx-> log, ngx_errno, ngx_open_dir_n "\"%s \ "fehlgeschlagen", Baum-> Daten); gib NGX_ERROR zurück; } PREV = CTX-> Daten; // Das hier übergebene Alloc ist 0, so dass es nicht die aktuelle Zweigstelle eingibt, wenn (ctx-> alloc) { data = ngx_alloc (ctx-> alloc, ctx-> log); if (data == null) { Goto scheiterte; } if (ctx-> init_handler (data, prev) == ngx_abort) { Goto scheiterte; } ctx-> data = data; } anders { Daten = NULL; } für ( ;; ) { ngx_set_errno (0); // Lesen Sie den Inhalt des aktuellen Unterverzeichnisses if (ngx_read_dir (& dir) == ngx_error) { Err = ngx_errno; if (err == ngx_enomorefiles) { rc = ngx_ok; } anders { ngx_log_error (ngx_log_crit, ctx-> log, err. ngx_read_dir_n "\"%s \ "fehlgeschlagen", Baum-> Daten); rc = ngx_error; } Goto gemacht; } len = ngx_de_namelen (& dir); name = ngx_de_name (& dir); ngx_log_debug2 (ngx_log_debug_core, ctx-> log, 0,, "Baumname %uz:" %s "", Len, Name); // Wenn das aktuelle Verzeichnis ist, bedeutet dies das aktuelle Verzeichnis und überspringen Sie dieses Verzeichnis, wenn (len == 1 && name [0] == ') { weitermachen; } // Wenn die aktuelle Lektüre .. bedeutet, dass es das Flag ist, in das vorherige Verzeichnis zurückzukehren, überspringen Sie dieses Verzeichnis, wenn (len == 2 && name [0] == '.' && name [1] == '.') { weitermachen; } file.len = baum-> len + 1 + len; // Die verfügbare Puffergröße aktualisieren if (Datei.len + ngx_dir_mask_len> buf.len) { if (buf.len) { ngx_free (buf.data); } buf.len = baum-> len + 1 + len + ngx_dir_mask_len; buf.data = ngx_alloc (buf.len + 1, ctx-> log); if (buf.data == null) { Goto scheiterte; } } p = ngx_cpymem (buf.data, baum-> data, baum-> len); *p ++ = '/'; ngx_memcpy (p, name, len + 1); Datei.data = buf.data; ngx_log_debug1 (ngx_log_debug_core, ctx-> log, 0,, "Baumpfad \"%s \ "", file.data); if (! Dir.valid_info) { if (ngx_de_info (Datei.data, & dir) == ngx_file_error) { ngx_log_error (ngx_log_crit, ctx-> log, ngx_errno, ngx_de_info_n "\"%s \ "fehlgeschlagen", file.data); weitermachen; } } // Wenn die aktuelle Datei eine Datei ist, rufen Sie ctx-> file_handler () auf, um den Inhalt der Datei zu laden if (ngx_de_is_file (& reichen)) { ngx_log_debug1 (ngx_log_debug_core, ctx-> log, 0,, "Baumdatei"%s \ "", file.data); // Setzen Sie die zugehörigen Attribute der Datei ctx-> size = ngx_de_size (& dire); ctx-> fs_size = ngx_de_fs_size (& dir); ctx-> access = ngx_de_access (& dir); ctx-> mtime = ngx_de_mtime (& dir); if (ctx-> file_handler (ctx, & file) == ngx_abort) { Goto scheiterte; } // 如果當前讀取到的是一個目錄,則首先調用設置的pre_tree_handler()方法,然后調用// ngx_walk_tree()方法,遞歸的讀取子目錄,最后調用設置的post_tree_handler()方法} else if (ngx_de_is_dir(&dir)) { ngx_log_debug1 (ngx_log_debug_core, ctx-> log, 0,, "Tree Enter Dir \"%s \ "", Datei.data); ctx-> access = ngx_de_access (& dir); ctx-> mtime = ngx_de_mtime (& dir); // Wenden Sie die vor-logische Lektüre des Verzeichnisses rc = ctx-> pre_tree_handler (CTX, & Datei) an; if (rc == ngx_abort) { Goto scheiterte; } if (rc == ngx_declined) { ngx_log_debug1 (ngx_log_debug_core, ctx-> log, 0,, "Tree Skip dir \"%s \ "", file.data); weitermachen; } // rekursiv das aktuelle Verzeichnis if (ngx_walk_tree (ctx, & file) == ngx_abort) { Goto scheiterte; } ctx-> access = ngx_de_access (& dir); ctx-> mtime = ngx_de_mtime (& dir); // post-logic anwenden, um das Verzeichnis zu lesen if (ctx-> post_tree_handler (ctx, & file) == ngx_abort) { Goto scheiterte; } } anders { ngx_log_debug1 (ngx_log_debug_core, ctx-> log, 0,, "Tree Special \"%s \ "", file.data); if (ctx-> spec_handler (ctx, & file) == ngx_abort) { Goto scheiterte; } } } fehlgeschlagen: rc = ngx_abort; Erledigt: if (buf.len) { ngx_free (buf.data); } if (Daten) { ngx_free (Daten); ctx-> data = prev; } if (ngx_close_dir (& dir) == ngx_error) { ngx_log_error (ngx_log_crit, ctx-> log, ngx_errno, ngx_close_dir_n "\"%s \ "fehlgeschlagen", Baum-> Daten); } rc zurückgeben; } Aus dem obigen Prozessfluss können wir feststellen, dass die tatsächliche Logik des Ladens von Dateien in der Methode ngx_http_file_cache_manage_file () liegt. static ngx_int_t ngx_http_file_cache_manage_file (ngx_tree_ctx_t *ctx, ngx_str_t *path) { ngx_msec_t verstrichen; ngx_http_file_cache_t *cache; cache = ctx-> Daten; // Fügen Sie die Datei zum freigegebenen Speicher hinzu if (ngx_http_file_cache_add_file (ctx, path)! = Ngx_ok) { (void) ngx_http_file_cache_delete_file (ctx, path); } // Wenn die Anzahl der geladenen Dateien die von Loader_files angegebene Nummer überschreitet, schlafen Sie für eine Weile, wenn (++ cache-> fateien> = cache-> lader_files) { ngx_http_file_cache_loader_sleep (cache); } anders { // Aktualisieren Sie die aktuelle zwischengespeicherte Zeit ngx_time_update (); // Berechnen Sie die Zeit zum Laden des aktuellen Threads verblüfft = ngx_abs ((ngx_msec_int_t) (ngx_current_msec - cache-> last); ngx_log_debug1 (ngx_log_debug_http, ngx_cycle-> log, 0,,,,,. "HTTP -Datei -Cache -Loader -Zeit verstrichen: %m", verstrichen); // Wenn der Ladevorgang länger dauert als die von Loader_Threshold angegebene Zeit, schlafen Sie für die angegebene Zeit if (verstrichen> = cache-> lader_threshold) { ngx_http_file_cache_loader_sleep (cache); } } return (ngx_quit || ngx_terate)? } Die Ladelogik ist hier relativ einfach. 4. Zusammenfassung In diesem Artikel wird zunächst erläutert, wie der NGINX Shared Memory und die spezifische Bedeutung jedes Parameters verwendet wird, dann das Implementierungsprinzip des gemeinsam genutzten Speichers und konzentriert sich schließlich auf die Initialisierung des gemeinsamen Speichers, die Arbeitsprinzipien des Cache -Managers und des Cache -Loaders. 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:
|
<<: Grafisches Tutorial zur Installation und Konfiguration von Mysql WorkBench
>>: So verwenden Sie vue-cli, um ein Projekt zu erstellen und es mit webpack zu verpacken
In diesem Artikelbeispiel wird der spezifische Co...
In diesem Artikelbeispiel wird der spezifische Co...
UPD 2020.2.26 Derzeit ist Ubuntu 20.04 LTS noch n...
1. Herunterladen Gehen Sie zur offiziellen Apache...
Inhaltsverzeichnis 1. Das ursprüngliche Array wir...
Front-End-Technologieschicht (Das Bild ist etwas e...
<meta name="viewport" content="B...
Heute bin ich auf ein kleines Problem gestoßen, a...
NodeJS kopiert die Dateien: Für den Kopiervorgang...
Inhaltsverzeichnis 1. Grundlegende Konzepte 2. En...
MySQL unterstützt Hash- und B-Tree-Indizes. InnoD...
Vorwort Ab MySQL 5.7.11 unterstützt MySQL die Dat...
1. readonly Nur-Lese-Attribut, so dass Sie den Wer...
Voraussetzung: content="width=750" <...
Inhaltsverzeichnis Vorwort Browser kompilierte Ve...