• Assurez la sécurité des applications de la bonne manière! Détectez, protégez, surveillez, accélérez et plus encore…
  • PHP est partout et est sans doute le langage le plus largement déployé sur le Web Internet.

    Cependant, il n'est pas exactement connu pour ses capacités de haute performance, en particulier lorsqu'il s'agit de systèmes hautement simultanés. Et c'est la raison pour laquelle pour de tels cas d'utilisation spécialisés, des langages tels que Node (oui, je sais, ce n'est pas un langage), Go et Elixir prennent le relais.

    Cela dit, vous pouvez faire beaucoup pour améliorer le Performances PHP sur votre serveur. Cet article se concentre sur la php-fpm côté des choses, qui est la manière naturelle de configurer sur votre serveur si vous utilisez Nginx.

    Au cas où tu sais quoi php-fpm est, n'hésitez pas à passer à la section sur l'optimisation.

    What is PHP-fpm?

    Peu de développeurs sont intéressés par DevOps côté des choses, et même parmi ceux qui le savent, très peu savent ce qui se passe sous le capot. Fait intéressant, lorsque le navigateur envoie une requête à un serveur exécutant PHP, ce n'est pas PHP qui forme le point le premier contact; à la place, c'est le serveur HTTP, dont les principaux sont Apache et Nginx. Ces «serveurs Web» doivent alors décider comment se connecter à PHP, et lui transmettre le type de requête, les données et les en-têtes.

    Le cycle requête-réponse dans le cas de PHP (Crédit image: ProinerTech)

    Dans les applications PHP modernes, la partie «rechercher un fichier» ci-dessus est le index.php, auquel le serveur est configuré pour déléguer toutes les demandes.

    Maintenant, la façon dont exactement le serveur Web se connecte à PHP a évolué, et cet article exploserait en longueur si nous devions entrer dans tous les détails. Mais en gros, à l'époque où Apache dominait en tant que serveur Web de choix, PHP était un module inclus à l'intérieur du serveur.

    Ainsi, chaque fois qu'une demande était reçue, le serveur démarrait un nouveau processus, qui inclurait automatiquement PHP, et l'exécutait. Cette méthode a été appelée mod_php, abréviation de «PHP en tant que module». Cette approche avait ses limites, que Nginx a surmontées avec php-fpm.

    In php-fpm la responsabilité de la gestion de PHP, les processus incombent au programme PHP au sein du serveur. En d'autres termes, le serveur Web (Nginx, dans notre cas), ne se soucie pas de l'emplacement de PHP et de la façon dont il est chargé, tant qu'il sait comment envoyer et recevoir des données. Si vous le souhaitez, vous pouvez considérer PHP dans ce cas comme un autre serveur en lui-même, qui gère certains processus PHP enfants pour les requêtes entrantes (donc, nous avons la requête atteignant un serveur, qui a été reçue par un serveur et transmise à un serveur - assez fou! :-P).

    Si vous avez effectué des configurations Nginx, ou même si vous les avez simplement introduites, vous rencontrerez quelque chose comme ceci:

         location ~ \ .php $ {try_files $ uri = 404; fastcgi_split_path_info ^ (. + \. php) (/.+) $; fastcgi_pass unix: /run/php/php7.2-fpm.sock; fastcgi_index index.php; inclure fastcgi_params; fastcgi_param SCRIPT_FILENAME $ racine_document $ fastcgi_script_name; }

    La ligne qui nous intéresse est la suivante: fastcgi_pass unix:/run/php/php7.2-fpm.sock;, qui indique à Nginx de communiquer avec le processus PHP via le socket nommé php7.2-fpm.sock. Ainsi, pour chaque demande entrante, Nginx écrit les données via ce fichier et, à la réception de la sortie, les renvoie au navigateur.

    Encore une fois, je dois souligner que ce n'est pas l'image la plus complète ou la plus précise de ce qui se passe, mais elle est tout à fait exacte pour la plupart des tâches DevOps.

    Cela dit, récapitulons ce que nous avons appris jusqu'à présent:

    • PHP ne reçoit pas directement les requêtes envoyées par les navigateurs. Les serveurs Web comme Nginx les interceptent d'abord.
    • Le serveur Web sait comment se connecter au processus PHP, et transmet toutes les données de la requête (littéralement tout colle) à PHP.
    • Lorsque PHP a fini de faire sa part, il renvoie la réponse au serveur Web, qui la renvoie au client (ou au navigateur, dans la plupart des cas).

    Ou graphiquement:

    Comment PHP et Nginx fonctionnent ensemble (Crédit image: DataDog)

    Excellent jusqu'à présent, mais vient maintenant la question à un million de dollars: qu'est-ce que PHP-FPM exactement?

    La partie «FPM» de PHP signifie «Fast Process Manager», qui est juste une façon sophistiquée de dire que PHP exécuté sur un serveur n'est pas un processus unique, mais plutôt des processus PHP qui sont générés, contrôlés et tués désactivé par ce gestionnaire de processus FPM. C'est à ce gestionnaire de processus que le serveur Web transmet les requêtes.

    Le PHP-FPM est un terrier entier en soi, alors n'hésitez pas à explorer si vous le souhaitez, mais pour nos besoins, cette explication fera l'affaire. 🙂

    Why optimize PHP-fpm?

    Alors pourquoi s'inquiéter de toute cette danse alors que tout va bien? Pourquoi ne pas laisser les choses telles qu'elles sont.

    Ironiquement, c'est précisément le conseil que je donne pour la plupart des cas d'utilisation. Si votre configuration fonctionne correctement et n'a pas de cas d'utilisation extraordinaires, utilisez les valeurs par défaut. Cependant, si vous cherchez à évoluer au-delà d'une seule machine, il est essentiel d'en extraire le maximum, car cela peut réduire de moitié les factures de serveur (voire plus!).

    Une autre chose à réaliser est que Nginx a été conçu pour gérer d'énormes charges de travail. Il est capable de gérer des milliers de connexions en même temps, mais si ce n'est pas le cas de votre configuration PHP, vous allez simplement gaspiller des ressources car Nginx devra attendre que PHP termine le processus actuel et accepte le ensuite, négativement définitivement les avantages que Nginx a été conçu pour offrir!

    Donc, avec cela à l'écart, regardons ce que nous changerions exactement en essayant d'optimiser php-fpm.

    How to optimize PHP-FPM?

    L'emplacement du fichier de configuration pour php-fpm peut différer sur le serveur, vous devrez donc faire des recherches pour le localiser. Vous pouvez utiliser commande find si sous UNIX. Sur mon Ubuntu, le chemin est /etc/php/7.2/fpm/php-fpm.conf. Le 7.2 est, bien sûr, la version de PHP que j'utilise.

    Voici à quoi ressemblent les premières lignes de ce fichier:

     ;;;;;;;;;;;;;;;;;;;;; ; Configuration FPM; ;;;;;;;;;;;;;;;;;;;;; ; Tous les chemins relatifs dans ce fichier de configuration sont relatifs à l'installation de PHP; préfixe (/ usr). Ce préfixe peut être modifié dynamiquement en utilisant le; Argument '-p' de la ligne de commande. ;;;;;;;;;;;;;;;;;; ; Options globales; ;;;;;;;;;;;;;;;;;; [global] ; Fichier Pid; Remarque: le préfixe par défaut est / var; Valeur par défaut: aucun pid = /run/php/php7.2-fpm.pid; Fichier journal des erreurs; S'il est défini sur "syslog", le journal est envoyé à syslogd au lieu d'être écrit; dans un fichier local. ; Remarque: le préfixe par défaut est / var; Valeur par défaut: log / php-fpm.log error_log = /var/log/php7.2-fpm.log

    Certaines choses devraient être immédiatement évidentes: la ligne pid = /run/php/php7.2-fpm.pid nous indique quel fichier contient l'identifiant de processus du php-fpm processus.

    Nous voyons aussi que /var/log/php7.2-fpm.log est ou php-fpm va stocker ses journaux.

    Dans ce fichier, ajoutez trois autres variables comme ceci:

    Emergency_restart_threshold 10 urgence_restart_interval 1 min process_control_timeout 10 s

    Les deux premiers paramètres sont mis en garde et indiquent php-fpm processus que si dix processus enfants échouent en une minute, le php-fpm le processus doit redémarrer.

    Cela peut ne pas sembler robuste, mais PHP est un processus de courte durée qui fuit de la mémoire, donc le redémarrage du processus principal en cas de défaillance élevée peut résoudre de nombreux problèmes.

    La troisième option, process_control_timeout, indique aux processus enfants d'attendre ce temps avant d'exécuter le signal reçu du processus parent. Ceci est utile dans les cas où les processus enfants sont au milieu de quelque chose lorsque les processus parents envoient un signal KILL, par exemple. Avec dix secondes en main, ils auront de meilleures chances de terminer leurs tâches et de sortir gracieusement.

    Étonnamment, ce qui ne la viande de php-fpm configuration! En effet, pour répondre aux requêtes Web, le php-fpm crée un nouveau pool de processus, qui aura une configuration distincte. Dans mon cas, le nom de la piscine s'est avéré être www et le fichier que je voulais éditer était /etc/php/7.2/fpm/pool.d/www.conf.

    Voyons comment ce fichier commence:

    ; Démarrez un nouveau pool nommé «www». ; la variable $ pool peut être utilisée dans n'importe quelle directive et sera remplacée par; nom du pool ('www' ici) [www]; Par préfixe de pool; Elle s'applique uniquement aux directives suivantes:; - «access.log»; - «slowlog»; - 'écouter' (unixsocket); - «chroot»; - «chdir»; - 'php_values'; - 'php_admin_values'; Lorsqu'il n'est pas défini, le préfixe global (ou / usr) s'applique à la place. ; Remarque: Cette directive peut également être relative au préfixe global. ; Valeur par défaut: aucun; préfixe = / chemin / vers / pools / $ pool; Utilisateur Unix / groupe de processus; Remarque: l'utilisateur est obligatoire. Si le groupe n'est pas défini, le groupe de l'utilisateur par défaut; sera utilisé. utilisateur = www-data group = www-data

    Un rapide coup d'œil à la fin de l'extrait ci-dessus résout l'énigme de la raison pour laquelle le processus serveur s'exécute comme www-data. Si vous rencontrez des problèmes d'autorisation de fichier lors de la configuration de votre site Web, vous avez probablement changé le propriétaire ou le groupe du répertoire en www-data, permettant ainsi au processus PHP de pouvoir écrire dans des fichiers journaux et télécharger des documents, etc.

    Enfin, nous arrivons à la source du problème, le paramètre du gestionnaire de processus (pm). En règle générale, vous verrez les valeurs par défaut comme quelque chose comme ceci:

    pm = dynamic pm.max_children = 5 pm.start_servers = 3 pm.min_spare_servers = 2 pm.max_spare_servers = 4 pm.max_requests = 200

    Alors, qu'est-ce que "dynamique»Signifie ici? Je pense que la documentation officielle explique le mieux cela (je veux dire, cela devrait déjà faire partie du fichier que vous éditez, mais je l'ai reproduit ici juste au cas où ce ne serait pas le cas):

     ; Choisissez comment le gestionnaire de processus contrôlera le nombre de processus enfants. ; Valeurs possibles: ; static - un nombre fixe (pm.max_children) de processus enfants; ; dynamic - le nombre de processus enfants est défini dynamiquement en fonction de; directives suivantes. Avec cette gestion de processus, il y aura; toujours au moins 1 enfant. ; pm.max_children - le nombre maximum d'enfants qui peuvent; être vivant en même temps. ; pm.start_servers - le nombre d'enfants créés au démarrage. ; pm.min_spare_servers - le nombre minimum d'enfants en «idle»; état (en attente de traitement). Si le nombre; des processus «inactifs» est moins que cela; nombre alors certains enfants seront créés. ; pm.max_spare_servers - le nombre maximum d'enfants en «inactif»; état (en attente de traitement). Si le nombre; des processus «inactifs» est plus grand que cela; nombre alors certains enfants seront tués. ; ondemand - aucun enfant n'est créé au démarrage. Les enfants seront fourchus quand; les nouvelles demandes se connecteront. Les paramètres suivants sont utilisés:; pm.max_children - le nombre maximum d'enfants qui; peut être vivant en même temps. ; pm.process_idle_timeout - Le nombre de secondes après quoi; un processus inactif sera tué. ; Remarque: cette valeur est obligatoire.

    On voit donc qu'il y a trois valeurs possibles:

    • Statique: Un nombre fixe de processus PHP sera maintenu quoi qu'il arrive.
    • Être dynamique.: Nous arrivons à spécifier le nombre minimum et maximum de processus qui php-fpm restera en vie à un moment donné.
    • à la demande: Les processus sont créés et détruits, à la demande.

    Alors, quelle est l'importance de ces paramètres?

    En termes simples, si vous avez un site Web à faible trafic, le paramètre «dynamique» est un gaspillage de ressources la plupart du temps. En supposant que vous avez pm.min_spare_servers mis à 3, trois processus PHP seront créés et maintenus même en l'absence de trafic sur le site Web. Dans de tels cas, «à la demande» est une meilleure option, laissant le système décider quand lancer de nouveaux processus.

    D'autre part, les sites Web qui gérer de gros volumes de trafic ou doit répondre rapidement sera puni dans ce cadre. Créer un nouveau processus PHP, en faire partie d'un pool et le surveiller, est une surcharge supplémentaire qu'il vaut mieux éviter.

    En utilisant pm = static corrige le nombre de processus enfants, laissant le maximum de ressources système à utiliser pour traiter les requêtes plutôt que pour gérer PHP. Si vous optez pour cette voie, sachez qu'elle a ses directives et ses pièges. Un article assez dense mais très utile à ce sujet est ici.

    Mot de la fin

    Étant donné que les articles sur les performances Web peuvent déclencher des guerres ou servir à embrouiller les gens, je pense que quelques mots s'imposent avant de fermer cet article. Le réglage des performances est autant une question de conjectures et d'arts sombres que de connaissance du système.

    Même si vous connaissez tous les php-fpm paramètres par cœur, le succès n'est pas garanti. Si vous n'aviez aucune idée de l'existence de php-fpm, alors vous n'avez pas besoin de perdre votre temps à vous en préoccuper. Continuez simplement à faire ce que vous faites déjà et continuez.

    En même temps, évitez de devenir un accro de la performance. Oui, vous pouvez obtenir des performances encore meilleures en recompilant PHP à partir de zéro et en supprimant tous les modules que vous n'utiliserez pas, mais cette approche n'est pas assez sensée dans les environnements de production. L'idée même d'optimiser quelque chose est de voir si vos besoins diffèrent des valeurs par défaut (ce qu'ils font rarement!), Et d'apporter des modifications mineures si nécessaire.

    Si vous n'êtes pas prêt à passer du temps à optimiser vos serveurs PHP, vous pouvez envisager de tirer parti d'une plate-forme fiable comme Kinsta qui s'occupe de l'optimisation des performances et de la sécurité.