Les modules nginx sont généralement divisés en trois catégories : gestionnaire, filtre et amont. Dans les chapitres précédents, les lecteurs ont déjà découvert les gestionnaires et les filtres. En utilisant ces deux types de modules, nginx peut facilement réaliser n'importe quel travail autonome.
Le module en amont permettra à nginx de transcender les limites d'une seule machine et de compléter la réception, le traitement et le transfert des données réseau.
La fonction de transfert de données fournit à nginx des capacités de traitement horizontal sur une seule machine, libérant nginx de la limitation de ne fournir qu'une seule fonction pour les nœuds terminaux et lui permettant d'avoir les fonctions de fractionnement, d'encapsulation et d'intégration au niveau niveau des applications réseau.
Le transfert de données est un élément clé de la capacité de nginx à créer une application réseau. Bien entendu, en raison de problèmes de coûts de développement, les composants clés d’une application réseau sont souvent initialement développés à l’aide de langages de programmation de haut niveau. Mais lorsque le système atteint une certaine échelle et que l'accent est davantage mis sur les performances, afin d'atteindre les objectifs de performances requis, les composants développés dans des langages de haut niveau doivent être structurellement modifiés.
En ce moment, en termes de coûts de modification, le module amont de nginx montre ses avantages car il est intrinsèquement rapide. En passant, le couplage hiérarchique et lâche fourni par le système de configuration de nginx rend le système évolutif à un niveau relativement élevé.
Essentiellement parlant, l'amont appartient au gestionnaire, mais il ne génère pas son propre contenu, mais obtient le contenu en demandant au serveur back-end, il est donc appelé en amont (en amont). L'ensemble du processus de demande et d'obtention du contenu de la réponse a été encapsulé dans nginx, de sorte que le module en amont n'a besoin que de développer plusieurs fonctions de rappel pour effectuer un travail spécifique tel que la construction de requêtes et l'analyse des réponses.
Les fonctions de rappel du module amont sont répertoriées comme suit :
Nom de la fonction | Description |
---|---|
create_request | Génère un tampon de requête (chaîne de tampons) envoyé au serveur backend, qui est utilisé lors de l'initialisation en amont |
reinit_request | Lorsqu'un serveur backend tombe en panne, nginx essaiera un autre serveur backend. Une fois que nginx a sélectionné un nouveau serveur, il appellera d'abord cette fonction pour réinitialiser l'état de fonctionnement du module en amont, puis reconnectera l'amont |
process_header | pour traiter l'en-tête d'informations renvoyé par le serveur back-end. Ce que l'on appelle l'en-tête est spécifié par le protocole de communication avec le serveur en amont, comme la partie en-tête du protocole HTTP, ou la partie état de réponse du protocole memcached |
abort_request | est appelée lorsque le client donne. la demande. Il n'est pas nécessaire d'implémenter la fonction de fermeture de la connexion au serveur back-end dans la fonction. Le système terminera automatiquement les étapes de fermeture de la connexion, donc généralement cette fonction n'effectuera aucun travail spécifique |
finalize_request | . est appelé une fois que la requête auprès du serveur back-end est terminée normalement. Cette fonction, comme abort_request, n'effectue généralement aucun travail spécifique |
input_filter | traite le corps de la réponse renvoyé par le serveur back-end. Le input_filter par défaut de nginx encapsulera le contenu reçu dans une chaîne tampon ngx_chain. Cette chaîne est localisée par le champ de pointeur out_bufs en amont, les développeurs peuvent donc utiliser ce pointeur pour obtenir les données texte renvoyées par le serveur back-end en dehors du module. Le module memcached implémente son propre input_filter. Ce module sera analysé en détail plus tard. |
input_filter_init | Initialisez le contexte du filtre d'entrée. Le input_filter_init par défaut de nginx renvoie directement |
memcache est un système de cache distribué hautes performances qui a été largement utilisé. memcache définit un protocole de communication privé afin que memcache ne soit pas accessible via des requêtes HTTP. Cependant, le protocole lui-même est simple et efficace, et Memcache est largement utilisé, de sorte que la plupart des langages et plates-formes de développement modernes fournissent une prise en charge de Memcache pour faciliter l'utilisation de Memcache par les développeurs.
nginx fournit le module ngx_http_memcached, qui fournit la fonction de lecture des données de Memcache, mais ne fournit pas la fonction d'écriture de données dans Memcache.
Le module amont utilise la méthode d'accès du module gestionnaire.
Dans le même temps, la conception du système de commande du module en amont suit également les règles de base du module handler : le module ne sera exécuté qu'après configuration du module.
Alors, quelle est la particularité du module amont ? C'est la fonction de traitement du module amont. Les opérations effectuées par la fonction de traitement du module amont incluent un processus fixe : (prenons le module memcached comme exemple, dans la fonction de traitement ngx_http_memcached_handler de memcached)
Créer la structure de données amont. :
ngx_http_upstream_t *u; if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } u = r->upstream;
Définissez la balise et le schéma du module. Le schéma ne sera désormais utilisé que pour les journaux et les balises seront utilisées pour la gestion de buf_chain :
ngx_str_set(&u->schema, "memcached://"); u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;
Définir la structure de données de la liste des serveurs backend en amont :
mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module); u->conf = &mlcf->upstream;
Définir la fonction de rappel en amont :
u->create_request = ngx_http_memcached_create_request; u->reinit_request = ngx_http_memcached_reinit_request; u->process_header = ngx_http_memcached_process_header; u->abort_request = ngx_http_memcached_abort_request; u->finalize_request = ngx_http_memcached_finalize_request; u->input_filter_init = ngx_http_memcached_filter_init; u->input_filter = ngx_http_memcached_filter;
Créer et définir la structure de données de l'environnement en amont :
ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t)); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ctx->request = r; ngx_http_set_ctx(r, ctx, ngx_http_memcached_module); u->input_filter_ctx = ctx;
Terminez l'initialisation en amont et terminez le travail :
r->main->count++; ngx_http_upstream_init(r); return NGX_DONE;
Cela est vrai pour tout module en amont, aussi simple que memcached, aussi complexe que proxy et fastcgi.
La plus grande différence entre les différents modules en amont dans ces 6 étapes apparaîtra dans les étapes 2, 3, 4 et 5.
Les étapes 2 et 4 sont faciles à comprendre. Les indicateurs définis par les différents modules et les fonctions de rappel utilisées sont définitivement différentes. L’étape 5 n’est pas non plus difficile à comprendre.
Seule l'étape 3 est un peu déroutante. Différents modules ont des stratégies très différentes pour obtenir la liste des serveurs backend. Certains sont aussi simples et clairs que Memcached, et d'autres sont aussi logiquement complexes que le proxy.
L'étape 6 est généralement cohérente entre les différents modules. Augmentez le nombre de 1 et renvoyez NGX_DONE.
Lorsque nginx rencontre cette situation, même s'il considérera que le traitement de la requête en cours est terminé, il ne libérera pas les ressources mémoire utilisées par la requête et ne fermera pas non plus la connexion avec le client.
La raison pour laquelle cela est nécessaire est que nginx a établi une relation un-à-un entre les requêtes en amont et les requêtes du client. Lors de l'utilisation ultérieure de ngx_event_pipe pour renvoyer la réponse en amont au client, ces données contenant les informations du client seront également utilisées. structure.
Liez les demandes en amont et les demandes des clients une à une. Cette conception présente des avantages et des inconvénients. L'avantage est qu'il simplifie le développement de modules et vous permet de vous concentrer sur la logique des modules. Cependant, les inconvénients sont tout aussi évidents. La conception un-à-un ne peut souvent pas répondre aux besoins d'une logique complexe.
Fonction de rappel : (en prenant toujours comme exemple la fonction de traitement du module memcached)
ngx_http_memcached_create_request : Il est très simple de générer une clé en fonction du contenu défini, puis de générer un "get $key" request et placez-le dans r ->upstream->Inside request_bufs.
ngx_http_memcached_reinit_request : Aucune initialisation requise.
ngx_http_memcached_abort_request : Aucune action supplémentaire requise.
ngx_http_memcached_finalize_request : Aucune action supplémentaire requise.
ngx_http_memcached_process_header : La fonction métier du module. Les informations d'en-tête du protocole memcache sont définies comme la première ligne de texte. Le code est le suivant :
#define LF (u_char) '\n' for (p = u->buffer.pos; p < u->buffer.last; p++) { if (*p == LF) { goto found; } }
Si le caractère LF (‘n’) n'est pas trouvé dans les données qui ont été lues dans le tampon. , la fonction renvoie NGX_AGAIN, indiquant que l'en-tête n'a pas été lu complètement, vous devez continuer à lire les données. nginx appellera à nouveau cette fonction après avoir reçu de nouvelles données.
nginx n'utilise qu'un seul cache lors du traitement de l'en-tête de réponse du serveur backend. Toutes les données se trouvent dans ce cache, donc lors de l'analyse des informations d'en-tête, il n'est pas nécessaire de prendre en compte le fait que les informations d'en-tête s'étendent sur plusieurs caches. Si l'en-tête est trop volumineux et ne peut pas être enregistré dans ce cache, nginx renverra un message d'erreur au client et enregistrera un journal d'erreurs, indiquant que le cache n'est pas assez grand.
La responsabilité importante de ngx_http_memcached_process_header est de traduire le statut renvoyé par le serveur backend en statut renvoyé au client. Par exemple :
u->headers_in.content_length_n = ngx_atoof(start, p - start); ··· u->headers_in.status_n = 200; u->state->status = 200; ··· u->headers_in.status_n = 404; u->state->status = 404;
u->state est utilisé pour calculer les variables liées en amont. Par exemple, u->state->status sera utilisé pour calculer la valeur de la variable "upstream_status". u->headers_in sera renvoyé sous forme de code d'état dans la réponse au client. Et u->headers_in.content_length_n définit la longueur de la réponse renvoyée au client.
Dans cette fonction, vous devez déplacer le pointeur de lecture vers l'arrière après avoir traité les informations d'en-tête, sinon ces données seront également copiées dans le corps de la réponse renvoyée au client, ce qui entraînera un contenu de corps incorrect. La fonction
ngx_http_memcached_process_header termine le traitement correct de l'en-tête de réponse et doit renvoyer NGX_OK. Si NGX_AGAIN est renvoyé, cela signifie que les données complètes n'ont pas été lues et que les données doivent continuer à être lues à partir du serveur backend. Renvoyer NGX_DECLINED n'a aucun sens. Toute autre valeur de retour est considérée comme un statut d'erreur, et nginx mettra fin à la requête en amont et renverra un message d'erreur.
ngx_http_memcached_filter_init : Correction de la longueur du contenu reçu du serveur backend. Car cette partie de la longueur n'est pas ajoutée lors du traitement de l'en-tête.
ngx_http_memcached_filter :
Le module memcached est un module rare avec une fonction de rappel pour traiter le texte.
Parce que le module memcached doit filtrer le CRLF "END" CRLF à la fin du texte, il implémente sa propre fonction de rappel de filtre.
La signification réelle du traitement du texte est d'encapsuler le contenu valide du texte reçu du serveur principal dans ngx_chain_t et de l'ajouter à la fin de u->out_bufs.
nginx ne copie pas les données, mais établit la structure de données ngx_buf_t pour pointer vers ces zones de mémoire de données, puis organise ces bufs par ngx_chain_t. Cette implémentation évite la relocalisation de mémoire à grande échelle et est l'une des raisons pour lesquelles nginx est efficace.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!