Reproduction de scénario
Ci-dessous, j'utiliserai un nginx natif pour reproduire ce processus sur ma machine virtuelle avec fedora26 installé. La version de nginx que j'utilise est la dernière 1.13.4
Premier démarrage de nginx
Vous pouvez voir que les deux. le maître et le travailleur sont déjà en cours d'exécution.
Ensuite, nous envoyons un signal sigusr2 au maître Lorsque le noyau nginx reçoit ce signal, il déclenchera une mise à jour à chaud.
Vous pouvez voir que le nouveau maître et les ouvriers créés par le maître sont déjà en cours d'exécution, à ce moment-là, nous envoyons alors un signal sigwinch à l'ancien maître. Après avoir reçu ce signal, l'ancien maître enverra sigquit à. ses ouvriers. , donc le processus de travail de l'ancien maître va se terminer :
À ce moment, seuls l'ancien maître, le nouveau maître et les ouvriers du nouveau maître restent en marche, ce qui est similaire à la situation de opération en ligne à ce moment-là.
Ensuite, nous utilisons la commande stop :
Nous constaterons que le nouveau maître et ses ouvriers sont sortis, tandis que l'ancien maître est toujours en cours d'exécution et a engendré des ouvriers. C’était la situation en ligne à cette époque.
En fait, ce phénomène est lié à la conception de nginx lui-même : lorsque l'ancien maître est prêt à créer un nouveau maître, il renommera le fichier nginx.pid en nginx.pid.oldbin, puis créera le nouveau maître. Le maître crée un nouveau nginx.pid. Ce fichier enregistrera le pid du nouveau maître. nginx pense qu'une fois la mise à jour à chaud terminée, la mission de l'ancien maître est presque terminée et il se terminera à tout moment, donc toutes les opérations ultérieures devraient être prises en charge par le nouveau maître. Bien sûr, il n'est pas valide de tenter une autre mise à jour à chaud en envoyant sigusr2 au nouveau maître sans que l'ancien maître ne se ferme. Le nouveau maître ignorera simplement ce signal et poursuivra son propre travail.
Analyse du problème
Ce qui est plus regrettable, c'est que la table lua que nous avons mentionnée ci-dessus, le fichier lua qui la définit, a déjà été chargée en mémoire par luajit et compilée en bytecode lors de l'exécution du hook init_by_lua. Donc évidemment, l'ancien maître ne doit pas. avoir cette table Lua, car la partie du code Lua qu'elle charge est une ancienne version.
Le code Lua qui indexe la table n'est pas utilisé lors de init_by_lua. Ces codes sont chargés dans le processus de travail à ce stade, les codes du répertoire du projet sont tous les plus récents, donc le processus de travail charge tous les codes les plus récents. si ces processus de travail traitent les requêtes pertinentes, une erreur d'exécution Lua se produira et la manifestation externe sera le http 500 correspondant.
Après avoir absorbé cette leçon, nous devons arrêter notre service nginx de manière plus rationnelle. Un script de démarrage et d'arrêt du service nginx plus raisonnable est donc nécessaire. Certains scripts diffusés sur Internet ne traitent pas de ce phénomène. Il faut se référer au script officiel fourni par nginx.
Ce code est cité du site officiel de nginx /etc/init.d/nginx .
Ensemble de signaux nginx
Ensuite, trions de manière exhaustive l'ensemble de signaux nginx. Les détails du code source ne seront pas impliqués ici. Les étudiants intéressés peuvent lire eux-mêmes le code source correspondant.
Nous avons deux façons d'envoyer des signaux au processus maître, l'une via le signal nginx -s et l'autre consiste à l'envoyer manuellement via la commande kill.
Le principe de la première méthode est de générer un nouveau processus, qui obtient le pid du processus maître via le fichier nginx.pid, puis envoie le signal correspondant au maître, puis se termine. Ce processus est appelé signaleur.
La deuxième méthode nous oblige à comprendre le mappage du signal nginx -s avec les signaux réels. Le tableau suivant présente leur relation de mappage :
signal d'opération
reload sighup
réouvrir sigusr1
stop sigterm
quit sigquit
hot update sigusr2 & sigwinch & sigquit
stop vs quit
stop envoie le signal sigterm, indiquant la nécessité de forcer la sortie , et quit est envoyé sigquit signifie quitter gracieusement. La différence spécifique est qu'une fois que le processus de travail a reçu le message sigquit (notez que le signal n'est pas envoyé directement, le message est donc utilisé à la place), il fermera le socket d'écoute, fermera la connexion actuellement inactive (la connexion qui peut être préemptée ), puis traitez-le à l'avance. Tous les événements de minuterie se terminent à la fin. Sauf circonstances particulières, quitter doit être utilisé au lieu de stop.
reload
Après avoir reçu le soupir, le processus maître réanalysera le fichier de configuration, demandera la mémoire partagée et une série d'autres tâches, puis générera un lot de nouveaux processus de travail et enfin enverra le message sigquit correspondant à l'ancien processus de travail et a finalement réalisé l'opération de redémarrage de manière transparente.
réouverture
Une fois que le processus maître a reçu sigusr1, il rouvrira tous les fichiers ouverts (tels que les journaux), puis enverra les informations sigusr1 à chaque processus de travail. Une fois que le processus de travail aura reçu le signal, il effectuera la même opération. La réouverture peut être utilisée pour la coupe de journaux. Par exemple, nginx fournit officiellement une solution :
Ici, sleep 1 est nécessaire, car entre le processus maître qui envoie le message sigusr1 au processus de travail et le processus de travail rouvrant réellement access.log. , il y a Pendant un certain temps, le processus de travail écrit toujours des journaux dans le fichier access.log.0. En dormant 1 seconde, l'intégrité des informations du journal access.log.0 est assurée (si la compression est effectuée directement sans veille, une perte de journal est susceptible de se produire).
mise à jour à chaud
Parfois, nous devons effectuer une mise à jour binaire à chaud. nginx inclut cette fonction lors de la conception, mais elle ne peut pas être effectuée via la ligne de commande fournie par nginx.
En reproduisant le problème ci-dessus, vous devriez avoir compris comment effectuer une mise à jour à chaud. Nous devons d'abord envoyer sigusr2 au processus maître actuel. Ensuite, le maître renommera nginx.pid en nginx.pid.oldbin, puis en créera un nouveau. one. process, le nouveau processus utilisera l'appel système execve pour remplacer l'image de processus actuelle par le nouveau fichier nginx elf et devenir le nouveau processus maître. Une fois le nouveau processus maître démarré, il effectuera l'analyse du fichier de configuration et d'autres opérations, puis lancera le nouveau processus de travail pour commencer à travailler.
Ensuite, nous envoyons le signal sigwinch à l'ancien maître, puis l'ancien processus maître enverra le message sigquit à son processus de travail, provoquant la sortie du processus de travail. L'envoi de sigwinch et sigquit au processus maître entraînera la fermeture du processus de travail, mais le premier ne provoquera pas non plus la fermeture du processus maître.
Enfin, si nous sentons que l'ancien processus maître a rempli sa mission, nous pouvons lui envoyer le signal sigquit pour le laisser sortir.
Comment le processus de travail gère le message de signal du maître
En fait, le processus maître communique avec le processus de travail, non pas en utilisant la fonction kill, mais en utilisant le canal nginx implémenté via le tube. À l'extrémité du canal (comme les informations de signal), le processus de travail reçoit des informations de l'autre extrémité. L'événement de canal nginx est ajouté au planificateur d'événements (comme epoll, kqueue) lorsque le processus de travail se lance, donc quand il y en a. les données envoyées par le maître, c'est-à-dire peuvent être notifiées par le planificateur d'événements.
nginx est conçu de cette façon pour une raison. En tant qu'excellent serveur proxy inverse, nginx recherche des performances extrêmement élevées et le gestionnaire de signaux interrompra l'exécution du processus de travail, provoquant la suspension de tous les événements pendant une fenêtre temporelle. est une certaine perte de performance.
Beaucoup de gens peuvent penser que lorsque le processus maître envoie des informations au processus de travail, le processus de travail répondra immédiatement avec les opérations correspondantes. Cependant, le processus de travail est très occupé. Il traite constamment les événements réseau et les événements de minuterie. canal Après le gestionnaire d'événements, nginx traite simplement quelques indicateurs. Ces actions sont en fait exécutées une fois qu'une série de planification d'événements est terminée. Par conséquent, il y a une fenêtre de temps entre les deux. Surtout lorsque l'entreprise est complexe et que le trafic est énorme, cette fenêtre peut être agrandie. C'est pourquoi le plan de coupe de journaux fourni par nginx nécessite officiellement 1 veille.
Bien sûr, nous pouvons également contourner le processus maître et envoyer des signaux directement au processus de travail. Les signaux que le travailleur peut gérer sont
effet de signal
sigint force exit
sigterm force exit
sigquit graceful exit
sigusr1 rouvrez le fichier.
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!