Nginx + php-fpm - Chaque processus php-fpm 70-100% cpu lors de l'exécution

8

J'ai une situation dans laquelle se produit ce qui suit:

  • Nous sommes sur linode avec 8 cœurs, 8 Go de RAM, 2,6 GHz - en utilisant nginx + php-fpm - nous obtenons des graphiques extrêmement élevés d'utilisation du processeur (que nous ne voulons pas être un si mauvais voisin VPS) ...

  • Nous avons environ moins de 100 utilisateurs sur le site à la fois - donc cette situation est également incroyablement embarrassante - que notre utilisation du processeur est très élevée.

  • Nous utilisons un Framework très inconnu, peut-être intensif en php, douteusement horrible au lieu d'autres frameworks bien connus, bien documentés et bien conçus comme wordpress ou drupal dans lesquels il y a BEAUCOUP de documentation sur la mise en cache (ainsi que des plugins) qui gèrent la mise en cache) php sur une plateforme nginx + php_fpm.

  • Ainsi, nous avons environ 6 processus php-fpm ouverts qui, en RUNNING, consomment individuellement de GRANDES quantités (30+ et souvent près de 99%) de cpu - et je n'ai pas vraiment la moindre idée de comment les empêcher d'utiliser autant de cpu . Je ne peux pas dire quels scripts php sont à l'origine de ces pics car ils se produisent tout le temps ... généralement seulement 1 ou 2 sont en cours d'exécution - mais lorsque tous les 6 s'exécutent, nous maximisons les 8 cpus.

  • Mon fichier pool.d / www.conf a les paramètres suivants:

    pm = dynamic
    pm.max_children = 10
    pm.start_servers = 4
    pm.min_spare_servers = 2
    pm.max_spare_servers = 6
    
  • Nous avons fait cette ^ configuration parce que, dans la façon dont je l'interprète, notre mémoire est en fait incroyable (htop montrant 472/7000 + mb utilisés, pas de swapping, etc.) et nous pourrions gérer beaucoup plus de processus et couper la ligne en attendant d'obtenir traité - MAIS malheureusement, puisque chaque processus est trop intense sur notre processeur lors de l'exécution - nous finissons par conduire notre CPU à travers le toit - donc nous ne pouvons pas gérer suffisamment de processus.

  • La question - que diable pouvons-nous faire pour réduire l'utilisation du processeur php-fpm pour que nous puissions augmenter les paramètres dans ce fichier de conf de pool pour php-fpm - et aussi oui, le /var/log/php5-fpm.log nous crie dessus pour augmenter nos enfants et ajuster / augmenter nos serveurs min / max / start. Mais cela rend notre moyenne de charge folle, comme indiqué précédemment. Comment pouvons-nous le faire sans nécessairement utiliser un cache ou quelles sont nos options?

  • Mon idée? J'ai lu des choses sur l'utilisation de cpulimit pour garantir qu'aucun processus ne prend plus qu'une quantité allouée de cpu - mais cela ralentira-t-il pour être inutilisable? Ou, ce faisant, nous pourrions augmenter notre capacité à exécuter plusieurs processus - je pensais également exécuter deux pools - un pour notre site Web orienté vers l'avant (ce que les clients ressentent) et un autre pour un backend (qui affecte notre site orienté vers l'avant lorsque le temps -des rapports de consommation sont en cours d'exécution).

  • J'ai passé quelques jours à faire des recherches, à googler, etc. sur ce sujet - et c'est difficile parce que la situation de chacun est si unique à son système - le problème réside dans un cadre aussi inouï, peut-être mal écrit - difficile de trouver une solution. Nous ne pouvons pas simplement supprimer ce cadre pour l'instant non plus - je dois trouver une solution quelconque.


MISE À JOUR: J'ai implémenté memcache pour stocker les sessions php - parce que le cadre repose fortement sur les sessions utilisateur et la nature de notre système est que les employés utilisent souvent plusieurs onglets à la fois - chacun revenant aux sessions pour confirmer les capacités / données utilisateur / etc. ... j'espère donc voir une augmentation des performances de cela - bienvenue à commenter cela si vous le souhaitez - je verrai comment cela se passera demain lorsque nous traverserons nos heures de pointe de volume plus élevé.

amurrell
la source
Nginx n'est pas très bon pour une application Web intensive en CPU - mais notre CPU élevé est mauvais - vraiment mauvais - et nous travaillons pour le réparer. Il n'y a pas de configuration maximale pour les clients max car il DEVRAIT être capable de prendre en charge un nombre décent de clients - mais l'utilisation élevée du processeur par processus biaise cette capacité. Nous sommes passés à Apache uniquement parce qu'il fait un peu mieux avec une utilisation élevée du processeur - mais finalement ce problème est plus indicatif d'un problème d'application Web et il peut prendre un certain temps à résoudre, mais il n'y a pas de temps comme le présent pour commencer à le réparer.
amurrell
Lorsque vous allez chez le médecin, et il vous dit de prendre certains médicaments - parce qu'il sait que vous n'écouterez pas les déclarations "arrêtez de boire du soda et de manger des fast-food" - c'est exactement pourquoi il n'y a pas eu de bonne réponse pour moi - parce que la vérité est , aucune configuration ou solution rapide n'a vraiment été appliquée - seule la triste vérité que nous devons modifier radicalement notre application Web elle-même.
amurrell
Heureusement, si vous rencontrez ce problème avec un framework populaire, vous pouvez avoir la possibilité d'utiliser la mise en cache et une documentation abondante à ce sujet - mais nous sommes sur une chose aléatoire obscure que nous ne pouvons pas changer sauf le framework lui-même. Yay!
amurrell
1
Donc, d'après ce que je comprends, opcache stocke votre code PHP en tant que binaire et peut être consommé par php-fpm beaucoup plus rapidement (mise en cache), mais vous devez également utiliser la mise en cache d'objets. Un exemple est de stocker une sortie de page entière comme un "objet" "dans quelque chose comme memcached. Cela mettrait en cache la sortie de la page (ou d'autres choses que vous voulez comme les sessions php, etc.) ... Ensuite, vous pouvez également utiliser du vernis qui est un proxy inverse - mais, fondamentalement, c'est un intermédiaire entre la demande et votre serveur afin que votre le serveur n'est pas directement touché par les demandes - et il fonctionne à partir de la mémoire pour servir les URL mises en cache.
amurrell
1
Le vernis est génial pour cela - stocker une copie en cache de ce qu'il a obtenu du serveur en mémoire - donc le vernis prend une grande partie de la charge. Mon employeur actuel est sur nginx et nous utilisons du vernis et memcached. Heureusement, le framework sur lequel nous sommes maintenant possède son propre mécanisme de mise en cache pour déterminer le cache de page (données de page générées). Lors de mon dernier travail, j'ai dû l'écrire moi-même dans le cadre - ce n'était pas amusant, mais a fonctionné. seule solution pour ne pas tuer totalement notre projet pendant que j'écrivais le mécanisme de mise en cache.
amurrell

Réponses:

6

Quelques points à considérer (excuses à l'avance si vous les avez déjà considérées): Tout d'abord, assurez-vous d'optimiser votre configuration nginx et d'appeler php-fpm uniquement lorsque cela est absolument nécessaire. La dernière chose que vous voulez faire est de laisser php gérer des choses comme les pages HTML statiques (ce qu'il fera avec plaisir).

Deuxièmement, puisque vous utilisez php-fpm, je suggère d'être plus agressif avec la durée de vie des enfants de php-fpm. Vous devez trouver le juste milieu entre les fils / enfants de courte durée et la stabilité. Les valeurs par défaut de php-fpm sont bien trop généreuses pour tout système de production, à mon humble avis. Plus un travailleur est autorisé à répondre aux demandes, plus il sera instable. Il y a également un risque plus élevé de fuites de mémoire, et si ce cadre auquel vous faites référence a des bogues comme des boucles infinies, ce qui peut vous causer des ennuis avec la charge du processeur, cela ne devrait pas faire de mal.

Je réduirais le nombre pm.max_requestsde vos pools de production. Je pense que la valeur par défaut est 200. Je commencerais à partir de 50 et verrais où cela vous mène.

A défaut / complémentaire à cela, vous pouvez également essayer ces options globales (AFAIK elles sont toutes désactivées par défaut):

emergency_restart_threshold 3
emergency_restart_interval 1m
process_control_timeout 5s

Qu'est-ce que ça veut dire? Si 3 processus enfants PHP-FPM se terminent avec SIGSEGV ou SIGBUS (c'est-à-dire un crash) en 1 minute, alors PHP-FPM est censé redémarrer automatiquement. Le processus enfant attend 5 secondes une réaction sur les signaux du maître.

Voici un bon aperçu de toutes les options de configuration que j'ai mentionnées ici, ainsi que d'autres: http://myjeeva.com/php-fpm-configuration-101.html

J'espère que ces conseils vous aideront! N'oubliez pas de modifier et d'observer, malheureusement, il ne semble pas y avoir de règle générale pour tout cela, comme vous l'avez observé, il y a trop de variables qui affectent le comportement et la stabilité de PHP.

Enfin, la fonctionnalité de limitation du processeur que vous avez demandée est documentée ici , mais je n'y recourrais que si vous épuisez toutes les autres options. Si vous choisissez ce chemin, je ferais certainement attention aux interactions possibles entre les ajustements PHP-FPM et votre configuration limits.conf. À ce stade, etckeeper peut être une bouée de sauvetage! :)

Bonne chance!

Rouben

Rouben
la source
Je vais essayer de limiter les max_requests demain - Il semble que chaque processus que nous autorisons veuille consommer le processeur, donc cela pourrait être une bonne idée. Nous utilisons les seuils de redémarrage d'urgence, mais mes chiffres étaient légèrement plus élevés - je vais essayer le vôtre et voir comment les choses se passent. Merci pour votre rigueur - très apprécié. Voulez-vous connaître vos réflexions sur la mise en cache? Je me demande si l'utilisation de la mise en cache php signifie que le cadre devrait être adapté pour le gérer. Je suis assez nouveau dans ce concept.
amurrell
3

Vous exécutez la mise en cache d'opcode, non?

C'était APC qui était le go-to ici, mais cela a été un buggy pendant un bon moment, et a été remplacé par Zend Opcache , qui fait maintenant partie de PHP depuis 5.5, et a un backport en PECL pour 5.3 et 5.4.

Michael Hampton
la source
Je suis intéressé par ce Zend OpCache - Nous en sommes au 5.3 - Si vous pouviez développer cette réponse, je l'apprécierais vraiment!
amurrell
Nous avions xcache - mais maintenant j'ai opté pour Zend Opcache et je l'ai installé et confirmé qu'il est opérationnel dans phpinfo (). Je vous ferai savoir si notre performance est meilleure en conséquence croise les doigts
amurrell
J'ai dû désactiver zend opcache pour l'instant - tout fonctionnait sauf tout fichier css ou js généré par php dynamique. J'ai essayé de mettre ces fichiers sur liste noire depuis opcache - mais soit la liste noire n'a pas fonctionné, soit je ne peux pas dire pourquoi opcache fait que nginx obtient 502 erreurs de passerelle incorrectes pour SEULEMENT ces fichiers. Ce dont j'ai besoin pour le modèle et ils font partie du mauvais cadre. Dans les journaux nginx, j'ai reçu des tonnes d'échecs de lecture - 104 erreurs de connexion entre pairs.
amurrell