Home  >  Article  >  Backend Development  >  Exploring the PHP-FPM process pool

Exploring the PHP-FPM process pool

一个新手
一个新手Original
2017-10-17 09:11:372034browse

PHP supports multi-process but not multi-threading; PHP-FPM runs multiple sub-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

As can be seen from the list, 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.

Exploration method: Simulate multi-threaded concurrent execution


1. What is a thread: Threads sometimes 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 have a few resources that are essential for operation, and share 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. Thread entities include programs, data and thread control blocks (TCB). TCB includes the following information:

(1) Thread status;

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

(3) a set of execution stacks;

(4) storage of local variables of each thread in main memory;

(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. Simulating 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...";

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


1. PHP-FPM configuration item pm.max_children = 5, simulated The .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)

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


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)

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)

Due to the upper limit of concurrent connection processing capacity of the server, 10, so the newly generated (simulated) thread registration can appear anywhere.

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)

It can be seen that the order of log records is consistent with the order of (simulated) thread generation . The basic unit of usleep delay is microseconds (us, 1 s = 1000000 us).

It can be seen from the above records:

1) These (simulation) threads are automatically generated after the first request to execute the script, a

(simulation) The thread then created another (simulation) thread;

2) Some of these

(simulation) threads are in the same sub-process space Generated and run in;

3) The time interval between the generation of adjacent (simulation) threads is very small, almost at the same time, or

the next (simulation) The thread is generated before the previous (simulated) thread has finished executing and exited; 4)

Multiple (simulated) threads can be executed 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 only one connection request can be processed 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 multiple pools to be defined, 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 Three types.

  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 each An upper limit on the number of requests handled by a subprocess, useful for dealing with 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 Exploring the PHP-FPM process pool. For more information, please follow other related articles on the PHP Chinese website!

Statement:
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