Detailed explanation of php-FPM process pool exploration

黄舟
Release: 2023-03-16 17:28:01
Original
2156 people have browsed it

The following editor will bring you an exploration of the PHP-FPM process pool. The editor thinks it’s pretty good, so I’ll share it with you now and give it as a reference. Let’s follow the editor to take a look

PHP supports multi-process but not multi-threading; PHP-FPM runs multiple child processes in the process pool to handle all connection requests concurrently. Check the status of the PHP-FPM process pool (pm.start_servers = 2) through ps as follows:


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
Copy after login

As can be seen from the list, there are two processes in the process pool www There are two child processes PID 8 and PID 9 that are still idle. Note: NLWP refers to the number of lightweight processes, that is, the number of threads.

What is PHP-FPM (FastCGI Process Manager)? PHP-FPM provides a process management method for PHP-CGI, which can effectively control memory and processes, and can smoothly reload PHP configuration. Its master process is resident in memory. FastCGI is a language-independent, scalable architecture CGI open extension. Its main behavior is to keep the CGI interpreter process in memory for a longer time, rather than fork-and-execute, and therefore obtain higher performance. FastCGI supports distributed deployment and can be deployed on multiple hosts other than the WEB server.

Method of Exploration: Simulate concurrent execution of multiple threads

1. What is a thread: Threads are sometimes also called lightweight processes (Lightweight Process, LWP), usually composed of thread ID, current instruction pointer (PC), register set and stack, is an entity in the process and is the basic unit independently scheduled by the system; the thread itself does not own system resources, only some running It shares all the resources owned by the process with other threads belonging to the same process. Due to the mutual constraints between threads, threads show discontinuity in their operation. Threads also have three basic states: ready, blocked and running. Since the process is the resource owner, the creation, cancellation and switching overhead are too high, so running multiple threads (Threads) simultaneously on a symmetric multiprocessor (SMP) is a more appropriate choice. The entity of the thread includes program, data and thread control block (TCB). TCB includes the following information:

(1) Thread status;

(2) When the thread When not running, saved on-site resources;

(3) A set of execution stacks;

(4) Main memory that stores local variables of each thread;

(5) Access main memory and other resources in the same process.

But using multiple processes will make the application more robust in the event that a process in the process pool crashes or is attacked.

2. Simulate 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...";
Copy after login

Summary of exploration: After running the above script, I found some results that were predictable but not what I had thought of

1. PHP-FPM configuration item pm.max_children = 5, simulated.thread record is as follows:


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)
Copy after login

The latest generated (simulated) thread registration appears in the red marked entry because the upper limit of the concurrent connection processing capacity of the process pool is 5, so it can only appear in the sixth The position after the bar.


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)
Copy after login

What’s interesting is that the registration time of the (simulation) thread represented by the green entry and the (simulation) thread represented by the red entry are the same, indicating that the two (simulation) threads are executed concurrently.

2. PHP-FPM configuration item pm.max_children = 10, simulated.thread record is as follows:


##

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)
Copy after login

Since the upper limit of the server's concurrent connection processing capacity reaches 10, the latest generated (simulated) thread registration can appear at any location.

3. Execute usleep(500) delay, simulated.thread record is as follows:

##

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)
Copy after login

is visible The logging order is consistent with the order in which (simulated) threads are spawned. The basic unit of usleep delay is microseconds (us, 1 s = 1000000 us).

It can be seen from the above records: 1) These (simulated) threads are automatically generated after the first request to execute the script. Yes, one (simulation) thread creates another (simulation) thread immediately;

2) Some of these (simulation) threads are generated and run in the same sub-process space;

3) The time interval between the generation of adjacent (simulated) threads is very small, almost at the same time, or the latter (simulated) thread is generated before the previous (simulated) thread has finished executing and exited;

4) Multiple (simulated) threads can execute concurrently.

So, the above implementation of simulating multi-thread concurrency is successful. The same sub-process in the PHP-FPM process pool can process multiple connection requests successively, but can only process one connection request at the same time. Unprocessed connection requests will enter the queue and wait for processing. In other words, the same child process does not have the ability to handle connection requests concurrently.

PHP-FPM Pool configuration: It allows the definition of multiple pools, and each pool can define different configuration items. The following is just a list of some other configuration items that I paid attention to during my exploration

1. listen: The address on which to accept FastCGI requests. It supports two communication protocols: TCP Socket and unix socket. You can set listen = [::]:9000.

2. listen.allowed_clients: List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect. This configuration item is a comma-separated list, such as listen.allowed_clients = 127.0.0.1,172.17.0.5 .

3. pm: Choose how the process manager will control the number of child processes. This configuration item sets the way FPM manages the process pool, including static, dynamic, and ondemand.

4. pm.max_requests: The number of requests each child process should execute before respawning. This can be useful to work around memory leaks in 3rd party libraries. Set the upper limit of the number of requests processed by each child process, for processing Useful for memory leaks in third-party libraries.

5. pm.status_path: The URI to view the FPM status page.

The above is the detailed content of Detailed explanation of php-FPM process pool exploration. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template