Apache atteignant MaxClients et verrouillant le serveur

9

J'ai actuellement un serveur Apache2 fonctionnant avec mpm-preforket mod_phpsur un OpenVZ VPS avec 512 Mo de RAM réel / 1024 Mo de mémoire vive (pas de swap). Après avoir exécuté quelques tests, j'ai constaté que la taille maximale du processus qu'Apache obtient est de 23 MaxClientsMo, j'ai donc défini 25 (23 Mo x 25 = 575 Mo, ok pour moi). J'ai décidé d'exécuter des tests de charge sur mon serveur et les résultats m'ont laissé perplexe.

J'utilise absur ma machine de bureau pour demander la page principale d'un blog wordpress.

Lorsque je cours abavec 24 connexions simultanées, tout semble aller bien. Bien sûr, le CPU augmente, la RAM libre diminue et le résultat est un temps de réponse d'environ 2-3 secondes par demande.

Mais si je lance abavec 25 connexions simultanées (ma limite de serveur), Apache se bloque juste après quelques secondes. Il commence à traiter les demandes, puis il cesse de répondre, le processeur revient à 100% inactif et abexpire. Le journal Apache indique qu'il a atteint MaxClients.

Lorsque cela se produit, Apache reste verrouillé avec 25 processus en cours d'exécution (ils sont tous en "W" si je vérifie l'état du serveur) et seulement après le TimeOutréglage, les processus commencent à mourir et le serveur recommence à répondre (dans mon cas, il est défini à 45).

Ma question: est-ce le comportement attendu? Pourquoi Apache meurt juste quand il atteint MaxClients? Si cela fonctionne avec 24 connexions, ne devrait-il pas fonctionner avec 25 connexions, en prenant peut-être juste plus de temps pour répondre à chaque demande et mettre en file d'attente le reste?

Cela me semble un peu étrange que tout enfant en cours d'exécution abpuisse à lui seul tuer un serveur Web simplement en configurant les connexions simultanées aux serveurs MaxClients.

Rodrigo Sieiro
la source

Réponses:

17

HA! J'ai finalement trouvé le problème moi-même. C'est plus lié à la programmation qu'à l'administrateur du serveur, mais j'ai quand même décidé de mettre la réponse ici car en recherchant sur Google, je ne suis pas le seul à avoir ce genre de problème (et depuis qu'Apache se bloque, la première supposition est qu'il y a un problème avec le serveur).

Le problème n'est pas avec Apache, mais avec mon Wordpress. Plus précisément avec mon thème. J'utilise un thème appelé Lightworld et il prend en charge l'ajout d'une image à l'en-tête du blog. Pour cela, il vérifie la taille de l'image en utilisant la fonction PHP getimagesize(). Puisque cette fonction ouvrait une autre connexion http au serveur pour obtenir l'image, chaque requête de abcréait une autre requête en interne depuis PHP. Comme j'utilisais tous les emplacements disponibles sur mon serveur, ces demandes PHP ont été placées dans la file d'attente, mais Apache n'a jamais pu y accéder car tous ses processus étaient verrouillés avec la demande d'origine en attente d'un emplacement pour terminer la demande interne PHP.

Fondamentalement, PHP mettait mon serveur dans un état de blocage, et Apache ne commencerait à fonctionner normalement qu'après expiration de ces connexions en attente de leur demande "enfant".

Après avoir supprimé cette fonction de mon thème, je peux maintenant abmon serveur avec autant de connexions simultanées que je veux, et Apache les met en file d'attente comme prévu.

Rodrigo Sieiro
la source
Merci d'avoir posté ceci ici, j'essaie de trouver un problème avec exactement les mêmes symptômes depuis quelques jours maintenant - pensez que nous avons aussi une impasse!
James Yale
comment avez-vous déterminé cela, je suis principalement intéressé par les journaux et les outils que vous avez utilisés pour déterminer la demande sortante secondaire.
Anirudh Goel
2

Ce qui se passe ici, c'est que vous avez 25 threads capables d'accepter les connexions et que vous envoyez 26 requêtes simultanées. Cette dernière demande se trouve dans la file d'attente de socket en fonction de la taille de votre backlog.

Le deuxième problème est que tout ce que vous exécutez, qui prend 2-3 secondes, prend suffisamment de temps pour répondre que les 25 connexions simultanées le ralentissent. sleep (1) peut fonctionner, mais, quelque chose où vous effectuez un verrouillage de fichier ou un verrouillage de table à partir de mysql, chaque demande parallèle peut attendre le avant d'être terminée jusqu'à ce qu'elle atteigne le délai d'expiration de 45 secondes.

23mb semble petit pour un processus apache avec mod_php et tous les modules chargés, donc, je soupçonne que vous pourriez voir ces processus apache prendre un peu plus de RAM pendant que votre application est en cours d'exécution. Vous ne pouvez pas vraiment faire de mathématiques avec MaxClients et la mémoire comme ça ... ce sera un peu proche, mais, vous ne savez jamais.

www-data  1495  0.1  0.9  56288 19996 ?        S    15:48   0:01 /usr/sbin/apache2 -k start
www-data  1500  0.0  0.5  49684 12436 ?        D    15:48   0:00 /usr/sbin/apache2 -k start

Il y a une machine, des processus 56M et 49M.

une autre machine:

www-data  7767  0.1  0.1 213732 14840 ?        S    14:55   0:08 /usr/sbin/apache2 -k start
www-data  8020  0.2  0.1 212424 13660 ?        S    14:57   0:08 /usr/sbin/apache2 -k start

une autre machine:

www-data 28509  0.8  0.1 161720 10068 ?        S    14:39   0:43 /usr/sbin/apache2 -k start
www-data 28511  0.8  0.1 161932 10344 ?        S    14:39   0:43 /usr/sbin/apache2 -k start

Ainsi, l'utilisation de la mémoire dépend beaucoup de la tâche, des modules qui sont chargés, etc. Sur les deux derniers, je pense que nous avons désactivé pdo & pdo_mysql car cette application ne les utilise pas.

La vraie question est, qu'est-ce que tu fais qui prend 3 secondes? Dans le monde d'aujourd'hui, c'est une éternité et considérée comme une application «bloquante». Apache ne mourra pas normalement, mais laissera ces threads dans la file d'attente du backlog jusqu'à ce qu'il puisse les traiter ou que les requêtes en attente expirent. Je crois que votre application entraîne probablement un dépassement de délai pour apache. Essayez-le sur une page contenant juste phpinfo (); et voyez si les résultats sont les mêmes.


la source
Merci pour tous les conseils! Je suis conscient que j'ai encore besoin d'optimiser beaucoup de choses (je viens de commencer à configurer le serveur il y a quelques jours et c'est ma première expérience avec un VPS), mais le problème était plus profond que cela ... J'ai posté une réponse au question expliquant quel était le problème dans mon cas spécifique.
Rodrigo Sieiro