web-dev-qa-db-fra.com

PHP5-FPM commence à utiliser de manière aléatoire beaucoup de ressources processeur

J'ai rencontré un problème vraiment étrange que je ne sais pas comment déboguer. J'ai une instance Amazon Ubuntu sous NGINX + PHP5-FPM + APC et un site Web y est installé. Il s'agit d'un cadre complexe PHP. En essayant de déboguer le problème, j’ai réduit le flux à ceci: beaucoup de grosses classes sont incluses, les objets principaux sont créés, la session est démarrée, un tableau de configuration est extrait de memcached, un fichier XML est extrait de memcache, HTML les modèles sont inclus, la sortie est envoyée au client.

Ensuite, j'utilise l'outil http_load pour mettre le site Web sous la charge de 20 requêtes par seconde: http_load -timeout 10 -rate 20 -fetches 10000 ./urls.txt

Ce qui se passe ensuite est plutôt étrange. top montre un tas de processus php5-fpm générant chacun quelques% de ressources processeur et tout se passe bien, comme ceci:

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
28440 www-data 20 0 67352 10m 5372 S 4.3 1.8 0:20.33 php5-fpm
28431 www-data 20 0 67608 10m 5304 S 3.3 1.8 0:16.77 php5-fpm
28444 www-data 20 0 67352 10m 5372 S 3.3 1.8 0:17.17 php5-fpm
28445 www-data 20 0 67352 10m 5372 S 3.0 1.8 0:16.83 php5-fpm
28422 www-data 20 0 67608 10m 5292 S 2.3 1.8 0:18.99 php5-fpm
28424 www-data 20 0 67352 10m 5368 S 2.0 1.8 0:16.59 php5-fpm
28438 www-data 20 0 67608 10m 5304 S 2.0 1.8 0:17.91 php5-fpm
28439 www-data 20 0 67608 10m 5304 S 2.0 1.8 0:23.34 php5-fpm
28423 www-data 20 0 67608 10m 5292 S 1.7 1.8 0:20.02 php5-fpm
28430 www-data 20 0 67608 10m 5300 S 1.7 1.8 0:15.77 php5-fpm
28433 www-data 20 0 67352 10m 5372 S 1.7 1.8 0:17.08 php5-fpm
28434 www-data 20 0 67608 10m 5292 S 1.7 1.8 0:18.56 php5-fpm
20648 memcache 20 0 51568 8192 708 S 1.3 1.3 2:51.06 memcached
28420 www-data 20 0 69876 13m 6300 S 1.3 2.3 0:20.89 php5-fpm
28421 www-data 20 0 67608 10m 5300 S 1.3 1.8 0:21.19 php5-fpm
28429 www-data 20 0 9524 2260 992 S 1.3 0.4 0:11.68 nginx
28435 www-data 20 0 67608 10m 5304 S 1.3 1.8 0:18.58 php5-fpm
28437 www-data 20 0 67352 10m 5372 S 1.3 1.8 0:17.87 php5-fpm
28441 www-data 20 0 67608 10m 5292 S 1.3 1.8 0:20.75 php5-fpm

Puis, après un laps de temps pouvant aller entre une seconde et quelques minutes, plusieurs processus (généralement deux) php5-fpm utilisent subitement tout le processeur:

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
28436 www-data 20 0 67608 10m 5304 R 48.5 1.8 0:23.68 php5-fpm
28548 www-data 20 0 67608 10m 5276 R 45.2 1.7 0:07.62 php5-fpm
28434 www-data 20 0 67608 10m 5292 R 2.0 1.8 0:23.28 php5-fpm
28439 www-data 20 0 67608 10m 5304 R 2.0 1.8 0:26.63 php5-fpm

À ce stade, tout reste bloqué et toutes les nouvelles demandes HTTP expirent. Si j'arrête l'outil http_load, le php5-fpm restera là pendant plusieurs minutes. Fait intéressant, si je fais php5-fpm stop, les processus php5-fpm disparaîtront, mais les commandes utilisant le système de fichiers auront des problèmes d’exécution. Par exemple. Si j'essaie de télécharger un fichier via ssh, top montrera ce qui suit en prenant plusieurs minutes pour lancer le téléchargement proprement dit:

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3298 sshd 20 0 7032 876 416 R 75.2 0.1 0:04.52 sshd
3297 sshd 20 0 7032 876 416 R 24.9 0.1 0:04.49 sshd

Le journal des erreurs PHP contient généralement ceci:

[05-Dec-2012 20:31:39] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 8 children, there are 0 idle, and 58 total children
[05-Dec-2012 20:32:08] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 16 children, there are 0 idle, and 66 total children

Le journal des erreurs Nginx contient les entrées suivantes:

2012/12/05 20:31:36 [error] 4800#0: *5559 connect() to unix:/dev/shm/php-fpm-www.sock failed (11: Resource temporarily unavailable) while connecting to upstream, client: ..., server: ec2-....compute-1.amazonaws.com, request: "GET /usa/index.php?page=contact_us HTTP/1.0", upstream: "fastcgi://unix:/dev/shm/php-fpm-www.sock:", Host: "ec2-....compute-1.amazonaws.com"

Le journal lent de PHP-FPM ne montre rien d'intéressant, la permutation ne se produit jamais et je n'ai pas réussi à rassembler d'autres faits intéressants sur le problème. Je suis passé par beaucoup d'itérations de modifications de fichiers de configuration, les plus récentes étant

nginx.conf: http://Pastebin.com/uaD56hJF

pool.d/www.conf: http://Pastebin.com/mFeeUULC

=== UPDATE 1 ===

configuration du site: http://Pastebin.com/qvinVNhB

=== UPDATE 2 ===

Je viens également de constater que dmesg signale des erreurs de ce type

[6483131.164331] php5-fpm[28687]: segfault at b6ec8ff4 ip b78c3c32 sp bff551f0 error 4 in ld-2.13.so[b78b5000+1c000]

=== UPDATE 3 ===

Nous avons une nouvelle instance micro Amazon EC2 juste au cas où, pour exclure les problèmes matériels possibles. De plus, j'utilise maintenant php-fastcgi pour exclure d'éventuels bogues fpm. Les autres différences sont mineures, je pense que la seule chose qui change est Ubuntu-Debian. Le même problème se produit toujours, sauf que le serveur parvient à récupérer légèrement après les secondes max_execution_time (puis à nouveau en flèche). 

J'ai essayé de jouer avec un test.php séparé et je ne suis pas sûr qu'il s'agisse du même problème, mais au moins dans top, il est identique. J'ai créé un test.php et inclus un groupe de bibliothèques qui appartiennent à notre framework. Les bibliothèques ne font rien sauf définir des classes ou inclure d'autres bibliothèques définissant des classes. J'ai vérifié avec APC et tout cela a été servi avec succès. J'ai commencé à faire pression sur test.php avec 200 requêtes par seconde et après un certain temps, la même chose s'est produite. Sauf que maintenant j'ai réussi à avoir des erreurs disant "trop ​​de fichiers ouverts". Cela ne se produit pas toujours cependant, parfois, il commence simplement à expirer sans générer l'erreur et quelques processus php sont bloqués, consommant tout le processeur. Je n’en ai joué qu’un petit peu, mais je pense qu’il ya une corrélation: en contrôlant le nombre de bibliothèques incluses ou en variant légèrement les requêtes/le débit en secondes, je peux contrôler le moment où la pointe du processeur va se produire. J'ai augmenté le nombre de variables pertinentes du système d'exploitation, mais le problème persiste, bien que cela prenne plus de temps (notez également que j'ai défini les limites sur des valeurs N fois supérieures au nombre total de demandes que j'ai effectuées lors des tests).

fs.file-max = 70000
...
*       soft    nofile   10000
*       hard    nofile  30000
...
worker_rlimit_nofile 10000;
...
(reloaded all the configs and made sure the new system vars actually took affect)

Donc, la meilleure et unique explication que je puisse trouver jusqu'ici est que même si APC est supposé extraire des fichiers de la mémoire, il est implémenté en interne d'une manière qui utilise toujours un descripteur de fichier chaque fois que PHP include- s sont appelés. Et soit parce qu’il les libère avec un retard, soit qu’à un moment malheureux, trop de demandes arrivent au même moment, le système exécute nos descripteurs et les nouvelles requêtes HTTP arrivent rapidement dans une file d’attente énorme. Je vais essayer de tester cela en quelque sorte.

12
Eugene

J'ai exploité un site Web avec une configuration similaire pendant de nombreux mois, avec un temps d'indisponibilité nul. J'ai jeté un coup d'œil à votre config, et ça a l'air bien. Cela étant dit, j’ai fait ma config il ya un moment.

Je envisagerais de réduire pm.max_requests = 10000 à quelque chose de plus raisonnable, tel que pm.max_requests = 500. Cela signifie simplement "n'utilisez pas chaque instance pour plus que X nombre de requêtes". Il est bon de ne pas avoir ce nombre trop élevé, car cela vous donne une résilience vis-à-vis des éventuels bogues du moteur PHP.

Je pense que le vrai problème réside probablement dans vos scripts PHP. C'est difficile à dire sans en savoir plus.

EDIT: Envisagez de ne pas commenter ;request_terminate_timeout = 0 et de le définir comme suit: request_terminate_timeout = 20. Vos scripts devront ensuite être terminés dans les 20 secondes. Vous constaterez probablement un changement de comportement, mais je pense que votre site peut rester en ligne. Cela indiquerait une erreur de script PHP.

EDIT2: Ma propre configuration php-fpm est la suivante:

[example.com]
listen = /var/run/sockets/example.com.socket
user = www-data
group = www-data
pm = dynamic
pm.start_servers = 5
pm.max_children = 15
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500
php_flag[expose_php] = off
php_flag[short_open_tag] = on

EDIT3: J'ai remarqué quelque chose d'inattendu dans votre configuration nginx, mais ce n'est peut-être rien.

Vous utilisez fastcgi_ignore_client_abort on;, ce qui pose des problèmes dans les processus de travail sous les anciennes versions de nginx. Je n'ai pas vu ce problème moi-même, car j'exécute une compilation personnalisée d'une version récente. Voici la description du problème sur le site nginx:

Dans la version 1.0.2, les demandes POST _ ne sont pas gérées correctement lorsque Fastcgi_ignore_client_abort est défini sur ce qui peut entraîner des défaillances de segment entre les opérateurs . Le fait de rétablir fastcgi_ignore_client_abort sur Default (désactivé) devrait résoudre ce problème.

9
Kevin A. Naudé

Astuce simple mais très utile pour réduire l’utilisation du processeur jusqu’à 50%, il suffit de modifier votre configuration php-fpm:

pm = dynamic

et le changer pour:

pm = ondemand
3
Animanga

Je suis en train de traverser ce même problème en ce moment, et je voulais vous indiquer ce post:

Comment déterminer quel script est exécuté dans le processus PHP-FPM

Ce doit être l'un de vos scripts PHP. Voyez si vous pouvez relier les points entre les ID de processus qui s’emballent et le fichier de script .php qui vous bloque.

C'est drôle, cela a été fait sur un serveur impeccablement rapide. Je pense qu'une mise à jour de WordPress (plugin ou noyau) pourrait être très responsable.

1
Berto

J'ai eu le même problème. J'ai essayé de reconfigurer PHP-FPM et NGINX et je ne suis pas allé très loin. Un de nos gars a désactivé v8js.php ( http://php.net/manual/en/book.v8js.php ) et le problème a été résolu. Je suggère de désactiver tous les modules php jusqu'à ce que vous trouviez le fauteur de troubles. Espérons que cela aide quelqu'un.

0
Allen

Le comportement de PHP-FPM sur mon serveur est le même que vous. goulot d'étranglement quelque part à coup sûr.
La question est la suivante: Comment trouver Bottleneck sur Nginx - PHP-FPM - Mysql? Le moyen le plus rapide de le savoir est de: Activer Slowlog pour PHP-FPM.
Ajoutez les lignes ci-dessous dans votre pool php-fpm.conf et assurez-vous que le chemin existe

request_slowlog_timeout = 10
slowlog = /var/log/php-fpm/slow.$pool.log

En lisant la trace de l'historique, vous pouvez comprendre pourquoi PHP-FPM a mis autant de temps processeur et de temps d'inactivité. Voici mes cas:

[28-Dec-2018 14:56:55]  [pool laravel] pid 19061
script_filename = /public_html/index.php
[0x00007efdda4d8100] hasChildren() /public_html/laravel/vendor/symfony/Finder/Iterator/ExcludeDirectoryFilterIterator.php:75
[0x00007ffe31cd9e40] hasChildren() unknown:0
[0x00007ffe31cda200] next() unknown:0
[0x00007ffe31cda540] next() unknown:0
[0x00007ffe31cda880] next() unknown:0
[0x00007efdda4d7fa8] gc() /public_html/laravel/vendor/laravel/framework/src/Illuminate/Session/FileSessionHandler.php:91
[0x00007efdda4d7e50] gc() /public_html/laravel/vendor/laravel/framework/src/Illuminate/Session/Middleware.php:159
[0x00007efdda4d7d48] collectGarbage() /public_html/laravel/vendor/laravel/framework/src/Illuminate/Session/Middleware.php:128
[0x00007efdda4d7c20] closeSession() /public_html/laravel/vendor/laravel/framework/src/Illuminate/Session/Middleware.php:79
[0x00007efdda4d7ac8] handle() /public_html/laravel/vendor/laravel/framework/src/Illuminate/Cookie/Queue.php:47
[0x00007efdda4d7930] handle() /public_html/laravel/vendor/laravel/framework/src/Illuminate/Cookie/Guard.php:51
[0x00007efdda4d7818] handle() /public_html/laravel/vendor/stack/builder/src/Stack/StackedHttpKernel.php:23
[0x00007efdda4d76e0] handle() /public_html/laravel/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:641
[0x00007efdda4d7598] run() 
/public_html/index.php:51

Le backtrace mentionne ces mots clés: 

"cookie" "session" "collectGarbage()" "laravel"

Je continue à chercher et TADA, Laravel en utilisant la méthode RANDOM pour effacer la session expirée. Et dans ma configuration, PHP utilise SSD pour gérer Session.
Lorsque le nombre de sessions devient "très grand" Cela a permis à PHP de passer plus de temps à gérer => une utilisation élevée de la CPU. 

Nous pouvons avoir de nombreux types de goulots d'étranglement, nous pouvons simplement le savoir lorsque nous l'avons "débogué".

Ayez une belle enquête.

0
minhhq