Maison  >  Article  >  développement back-end  >  Exploration basée sur le pool de processus PHP-FPM

Exploration basée sur le pool de processus PHP-FPM

coldplay.xixi
coldplay.xixiavant
2020-07-21 17:18:482453parcourir

Exploration basée sur le pool de processus PHP-FPM

PHP prend en charge le multi-processus mais pas le multi-threading ; PHP-FPM exécute plusieurs sous-processus dans le pool de processus pour gérer toutes les demandes de connexion simultanément. Vérifiez l'état du pool de processus PHP-FPM (pm.start_servers = 2) via ps comme suit :

root@d856fd02d2fe:~# ps aux -L
USER  PID LWP %CPU NLWP %MEM VSZ RSS TTY  STAT START TIME COMMAND
root   1  1 0.0 1 0.0 4504 692 ?  Ss 13:10 0:00 /bin/sh /usr/local/php/bin/php-fpm start
root   7  7 0.0 1 0.4 176076 19304 ?  Ss 13:10 0:00 php-fpm: master process (/usr/local/php/etc/php-fpm.conf)
www-data  8  8 0.0 1 0.2 176076 8132 ?  S 13:10 0:00 php-fpm: pool www
www-data  9  9 0.0 1 0.2 176076 8132 ?  S 13:10 0:00 php-fpm: pool www
root  10 10 0.0 1 0.0 18376 3476 ?  Ss 14:11 0:00 bash
root  66 66 0.0 1 0.0 34420 2920 ?  R+ 15:13 0:00 ps aux -L

Comme le montre la liste, il y a deux processus enfants inactifs, PID 8 et PID dans le processus. piscine www 9. Remarque : NLWP fait référence au nombre de processus légers, c'est-à-dire au nombre de threads.

Qu'est-ce que PHP-FPM (FastCGI Process Manager) ? PHP-FPM fournit une méthode de gestion de processus pour PHP-CGI, qui peut contrôler efficacement la mémoire et les processus, et recharger en douceur la configuration PHP. Son processus maître réside en mémoire. FastCGI est une extension ouverte CGI à architecture évolutive et indépendante du langage. Son comportement principal est de conserver le processus d'interpréteur CGI en mémoire plus longtemps, plutôt que de le forker et de l'exécuter, et donc d'obtenir des performances plus élevées. FastCGI prend en charge le déploiement distribué et peut être déployé sur plusieurs hôtes autres que le serveur WEB.

Méthodes à explorer : simuler une exécution simultanée multithread

Recommandations d'apprentissage associées : Programmation PHP de l'entrée à la maîtrise

1. Qu'est-ce qu'un thread : Un thread est parfois appelé un processus léger (LWP). Il se compose généralement d'un ID de thread, du pointeur d'instruction actuel (PC), d'un ensemble de registres. et une pile. Une entité dans le processus est l'unité de base qui est planifiée indépendamment par le système ; le thread lui-même ne possède pas de ressources système, seulement certaines ressources essentielles au fonctionnement, et partage toutes les ressources possédées par le processus avec d'autres threads. appartenant au même processus. En raison des contraintes mutuelles entre les threads, les threads présentent une discontinuité dans leur fonctionnement. Les threads ont également trois états de base : prêt, bloqué et en cours d'exécution. Étant donné que le processus est propriétaire de la ressource, les frais généraux de création, d'annulation et de commutation sont trop élevés, donc exécuter plusieurs threads (Threads) simultanément sur un multiprocesseur symétrique (SMP) est un choix plus approprié. Les entités de thread incluent les programmes, les données et les blocs de contrôle de thread (TCB). TCB comprend les informations suivantes :

(1) état du thread

(2) lorsque le thread n'est pas en cours d'exécution ; , ressources enregistrées sur site ;

(3) un ensemble de piles d'exécution

(4) mémoire principale pour stocker les variables locales de chaque thread ;

(5) Accédez à la mémoire principale et à d'autres ressources dans le même processus.


Mais l'utilisation de plusieurs processus rendra l'application plus robuste en cas de panne ou d'attaque d'un processus du pool de processus.

2. Simuler le multi-threading :

<?php
/**
 * PHP 只支持多进程不支持多线程。
 *
 * PHP-FPM 在进程池中运行多个子进程并发处理所有连接,
 * 同一个子进程可先后处理多个连接请求,但同一时间
 * 只能处理一个连接请求,未处理连接请求将进入队列等待处理
 *
 */

class SimulatedThread
{
 //模拟线程
 private $thread;

 //主机名
 private $host = &#39;tcp://172.17.0.5&#39;;

 //端口号
 private $port = 80;

 public function __construct()
 {
  //采用当前时间给线程编号
  $this->thread = microtime(true);
 }

 /**
  * 通过socket发送一个新的HTTP连接请求到本机,
  * 此时当前模拟线程既是服务端又是模拟客户端
  *
  * 当前(程序)子进程sleep(1)后会延迟1s才继续执行,但其持有的连接是继续有效的,
  * 不能处理新的连接请求,故这种做法会降低进程池处理并发连接请求的能力,
  * 类似延迟处理还有time_nanosleep()、time_sleep_until()、usleep()。
  * 而且sleep(1)这种做法并不安全,nginx依然可能出现如下错误:
  * “epoll_wait() reported that client prematurely closed connection,
  * so upstream connection is closed too while connecting to upstream”
  *
  * @return void
  */
 public function simulate()
 {
  $run = $_GET[&#39;run&#39;] ?? 0;
  if ($run++ < 9) {//最多模拟10个线程
   $fp = fsockopen($this->host, $this->port);
   fputs($fp, "GET {$_SERVER[&#39;PHP_SELF&#39;]}?run={$run}\r\n\r\n");
   sleep(1);//usleep(500)
   fclose($fp);
  }

  $this->log();
 }

 /**
  * 日志记录当前模拟线程运行时间
  *
  * @return void
  */
 private function log()
 {
  $fp = fopen(&#39;simulated.thread&#39;, &#39;a&#39;);
  fputs($fp, "Log thread {$this->thread} at " . microtime(true) . "(s)\r\n");

  fclose($fp);
 }
}

$thread = new SimulatedThread();
$thread->simulate();
echo "Started to simulate threads...";

Résumé de l'exploration : Après avoir exécuté le script ci-dessus, j'ai trouvé quelque chose de prévisible mais pas ce que je voulais. avait expérimenté. Les résultats qui me viennent à l'esprit

1. L'élément de configuration PHP-FPM pm.max_children = 5, l'enregistrement simulé.thread est le suivant :

Log thread 1508054181.4236 at 1508054182.4244(s)
Log thread 1508054181.4248 at 1508054182.4254(s)
Log thread 1508054181.426 at 1508054182.428(s)
Log thread 1508054181.6095 at 1508054182.6104(s)
Log thread 1508054182.4254 at 1508054183.4262(s)
Log thread 1508054183.4272 at 1508054183.4272(s)
Log thread 1508054182.4269 at 1508054183.4275(s)
Log thread 1508054182.4289 at 1508054183.43(s)
Log thread 1508054182.6085 at 1508054183.6091(s)
Log thread 1508054182.611 at 1508054183.6118(s)

Le dernier enregistrement de thread généré (simulation) apparaît à l'emplacement marqué en rouge car la limite supérieure de la capacité de traitement des connexions simultanées du pool de processus est de 5, il ne peut donc apparaître qu'au sixième emplacement et aux suivants.

Log thread 1508058075.042 at 1508058076.0428(s)
Log thread 1508058075.0432 at 1508058076.0439(s)
Log thread 1508058075.0443 at 1508058076.045(s)
Log thread 1508058075.6623 at 1508058076.6634(s)
Log thread 1508058076.0447 at 1508058077.0455(s)
Log thread 1508058076.046 at 1508058077.0466(s)
Log thread 1508058077.0465 at 1508058077.0466(s)
Log thread 1508058076.0469 at 1508058077.0474(s)
Log thread 1508058076.6647 at 1508058077.6659(s)
Log thread 1508058076.6664 at 1508058077.6671(s)

Ce qui est intéressant c'est que l'heure d'enregistrement du fil (simulé) représenté par l'entrée verte et du fil (simulé) représenté par l'entrée rouge sont les mêmes, indiquant que les deux fils (simulés) sont exécutés concurremment.

2. Élément de configuration PHP-FPM pm.max_children = 10, l'enregistrement simulé.thread est le suivant :

Log thread 1508061169.7956 at 1508061170.7963(s)
Log thread 1508061169.7966 at 1508061170.7976(s)
Log thread 1508061169.7978 at 1508061170.7988(s)
Log thread 1508061170.2896 at 1508061171.2901(s)
Log thread 1508061170.7972 at 1508061171.7978(s)
Log thread 1508061171.7984 at 1508061171.7985(s)
Log thread 1508061170.7982 at 1508061171.7986(s)
Log thread 1508061170.7994 at 1508061171.8(s)
Log thread 1508061171.2907 at 1508061172.2912(s)
Log thread 1508061171.2912 at 1508061172.2915(s)

En raison d'une connexion simultanée traitement côté serveur La capacité est limitée à 10, de sorte que les enregistrements de threads nouvellement générés (simulés) peuvent apparaître n'importe où.

3. Exécutez le délai usleep(500), l'enregistrement simulé.thread est le suivant :

Log thread 1508059270.3195 at 1508059270.3206(s)
Log thread 1508059270.3208 at 1508059270.3219(s)
Log thread 1508059270.322 at 1508059270.323(s)
Log thread 1508059270.323 at 1508059270.324(s)
Log thread 1508059270.3244 at 1508059270.3261(s)
Log thread 1508059270.3256 at 1508059270.3271(s)
Log thread 1508059270.3275 at 1508059270.3286(s)
Log thread 1508059270.3288 at 1508059270.3299(s)
Log thread 1508059270.3299 at 1508059270.331(s)
Log thread 1508059270.3313 at 1508059270.3314(s)

Séquence d'enregistrement du journal visible et (simulée) génération de threads L'ordre est cohérent. L'unité de base du délai de mise en veille est la microseconde (us, 1 s = 1 000 000 us).

Comme le montrent les enregistrements ci-dessus :

1) Ces threads (simulés) sont automatiquement générés après la première requête pour exécuter le script , un thread (de simulation) crée immédiatement un autre thread (de simulation) ;

2) Certains de ces threads (de simulation) sont générés et exécutés dans le même espace de sous-processus ; L'intervalle de temps entre la génération des threads adjacents (simulés) est très petit, presque en même temps, ou ce dernier thread (simulé) est généré avant que le thread précédent (simulé) ait fini de s'exécuter et de se fermer

; 4) Plusieurs threads (simulés) peuvent s’exécuter simultanément.

Ainsi, l'implémentation ci-dessus de simulation de concurrence multithread est réussie. Le même sous-processus dans le pool de processus PHP-FPM peut traiter plusieurs demandes de connexion successivement, mais ne peut traiter qu'une seule demande de connexion en même temps. Les demandes de connexion non traitées entreront dans la file d'attente et attendront d'être traitées. En d’autres termes, le même processus enfant n’a pas la capacité de gérer simultanément les demandes de connexion.

Configuration du pool PHP-FPM : elle permet de définir plusieurs pools, et chaque pool peut définir différents éléments de configuration. Ce qui suit n'est qu'une liste d'autres éléments de configuration auxquels j'ai prêté attention lors de mon exploration

1 écouter : L'adresse sur laquelle accepter les requêtes FastCGI. Il prend en charge deux protocoles de communication : TCP Socket et Unix. prise. Vous pouvez définir Listen = [::]:9000.

2. Listen.allowed_clients : Liste des adresses (IPv4/IPv6) des clients FastCGI autorisés à se connecter. Cet élément de configuration est une liste séparée par des virgules, telle que Listen.allowed_clients = 127.0.0.1,172.17.0.5.

15h : Choisissez comment le gestionnaire de processus contrôlera le nombre de processus enfants. Cet élément de configuration définit la façon dont FPM gère le pool de processus, y compris statique, dynamique et à la demande.

4. pm.max_requests : Le nombre de requêtes que chaque processus enfant doit exécuter avant de réapparaître. Cela peut être utile pour contourner les fuites de mémoire dans les bibliothèques tierces. Définir la limite supérieure du nombre de requêtes traitées par chacune. processus enfant, pour le traitement Utile pour les fuites de mémoire dans les bibliothèques tierces.

5. pm.status_path : L'URI pour afficher la page d'état FPM.

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer