Linux--The source code parsing and model of PHP-FPM

Source: Internet
Author: User
Tags fpm readable unix domain socket

1. Process management Mode

The PHP-FPM consists of 1 master processes and n worker processes. Where the worker process is forked by the master process.

PHP-FPM has 3 worker process management modes.

1. Static

Call Fpm_children_make (wp,0,0,1) function during initialization to fork out Pm.max_children number of worker processes, and subsequently no longer dynamically increase or decrease the number of worker processes

2. Dynamic

The Fpm_children_make (wp,0,0,1) function is called when initializing to fork out a pm.start_servers number of worker processes, and then the heartbeat event is triggered every 1 seconds fpm_pctl_perform_idle_server _maintenance () to maintain the number of idle Woker processes: If the number of idle worker processes is more than pm.max_spare_servers, the kill process, if less than pm.min_spare_servers, is the fork process.

3. Ondemand

The worker process is not generated when initializing, but registering the event ondemand_event monitoring listening_socket. When Listen_socket receives the request, it first checks to see if there are idle worker processes that have been generated and uses this idle process if it exists, otherwise fork a new process. A heartbeat event triggered every 1 seconds fpm_pctl_perform_idle_server_maintenance () will kill the worker process that has idle time exceeding pm.process_idle_timeout

2. Standard IO

The typical flow of fastcgi is as follows:

(1) Web server (for example, Nginx or Apache) accepts a request. The Web server then connects to the FASTCGI application through a UNIX domain socket or TCP socket.

(2) fastcgi application can choose to accept or reject this connection. If the connection is accepted, the FASTCGI application attempts to read from the stream to a packet

(3) The first packet sent by Web server is Begin_request packet. The Begin_request packet contains a unique REQUEST ID. All subsequent packet of the request are marked with this ID.

Unix system, the standard input file descriptor is 0, the standard output file descriptor is 1, the standard error output file descriptor is 2, the macro is defined as follows:

#define STDIN_FILENO 0

#define Stdout_fileno 1

#define Stderr_fileno 2

PHP-FPM redirects these three standard IO.

In the master process, Stdin_fileno (0) and Stdout_fileno (1) are redirected to "/dev/null". Stderr_fileno (2) redirects to Error_log.

In the worker process, Stdin_fileno (0) redirects to Listening_socket. If Catch_workers_output is no, Stdout_fileno (1) and Stderr_fileno (2) are redirected to "/dev/null". Otherwise, Stdout_fileno (1) redirects to the write end of the 1 pipe, and the FD read end of the pipe is stored on the fd_stdout element of the child node structure corresponding to the child linked list of the master process. Similarly, Stderr_fileno (2) redirects to the write end of 1 pipes, while the read-side FD of the pipe is stored on the Fd_stderr element of the child node structure corresponding to the child linked list of the master process. The above two driven by master processes in the master process of the pipe read the reactor to listen.

3. interprocess communication model

Inter-process communication in PHP-FPM is mainly divided into

1. Communication between the master process and the worker process

There are two pipe lines between the master process and the worker process. The worker process writes information to Stdout_file or Stderr_fileno, and the master process writes log after it receives the information. Master process monitors two pipe with reactor

2. Communication between WEB server and worker processes

Worker process blocking on the accept (listening socket) listening Web server

3. Communication between the WEB server and the master process

When the PM mode is OnDemand, the master process registers the Listening_socket listener event in reactor. When a request arrives, the master process generates a worker process

The process model used by PHP-FPM is the process pool. The worker process inherits the socket FD from the master process socket (), bind (), listen () and blocks directly on the accept (). When there is a request coming, a worker process in the process pool accepts the request. When the worker process finishes executing, it returns to the process pool waiting for the new request. This is actually the leader/follower pattern. In Leader/follower mode, only leader blocking waits and other processes are in sleep. Similarly, in FPM, the new request will only wake up a worker process because the Linux kernel solves the cluster problem of accept (). Here, leader's succession is determined by the Linux kernel (you can, of course, guard the accept code snippet with a mutex to ensure that there is only one leader).

The worker process handles all IO and logic. The master process is responsible for generating and destroying worker processes. The master process's reactor registers three readable events and four timer events. When PM is OnDemand, an additional readable event is registered. Three readable events are 1 signal events, 2 pipe events, respectively.

FPM_EVENT_S structure:

structfpm_event_s {intFD; structtimeval timeout; structTimeval frequency; void(*callback) (structfpm_event_s *, Short,void*); void*Arg; intflags; intindex;  Shortwhich; };

Flags represents the type of the event. There are three values for the flags in FPM:

Fpm_ev_read: Readable events

Fpm_ev_persist: Heartbeat Events

Fpm_ev_read | Fpm_ev_edge: A readable event triggered by the edge

which represents which event queue the event is located in. There are two types of values:

Fpm_ev_read: In the readable event queue

Fpm_ev_timeout: In Timer event queue

The structure of the event queue is a doubly linked list

struct fpm_event_queue_s {         struct fpm_event_queue_s *prev;          struct fpm_event_queue_s *next;          struct fpm_event_s *staticstruct fpm_event_queue_s *fpm_event_queue_ Timer = NULL; Static struct fpm_event_queue_s *fpm_event_queue_fd = NULL;  

The Fpm_event_queue_timer is the Timer event queue, and the FPM_EVENT_QUEUE_FD is a readable event queue. The Timer event queue does not employ the smallest heap, red black tree or event wheel structure, because this queue is very small and there is no need to use these complex structures. However, if the Timer event queue is changed to the ascending list, the performance should be improved.

FD and index are used only in readable events. FD represents the file descriptor being listened to. The value of index is related to which IO multiplexing API is used. In Epoll and select, the value of index is equal to the value of FD. In poll, index is the subscript in which the FD is positioned in the description descriptor fds[]. In the heartbeat event, FD = = -1,index = =-1.

struct Timeval timeout and struct Timeval frequency are only used in heartbeat events. Frequency indicates how many times a heartbeat event is triggered, and timeout indicates the next time the heartbeat event is triggered, usually by now and frequency. In a readable event, these two structures are not set.

Signal_fd_event Events

First look at the signal processing in FPM.

intFpm_signals_init_main ()/* {{{ */{         structSigaction Act; /*Create Socketpair*/         if(0> Socketpair (Af_unix, Sock_stream,0, SP)) {Zlog (Zlog_syserror,"failed to init Signals:socketpair ()"); return-1; }         /*set two sockets to Nonblock*/         if(0> fd_set_blocked (sp[0],0) ||0> fd_set_blocked (sp[1],0) {zlog (Zlog_syserror,"failed to init signals:fd_set_blocked ()"); return-1; }         /*if the program finishes running successfully, the two FD is automatically closed*/         if(0> Fcntl (sp[0], F_SETFD, fd_cloexec) | |0> Fcntl (sp[1], F_SETFD, fd_cloexec) {Zlog (Zlog_syserror,"falied to Init signals:fcntl (F_SETFD, fd_cloexec)"); return-1; } memset (&act,0,sizeof(act)); /*set the signal processing function to Sig_handler*/Act.sa_handler=Sig_handler; /*Add all signals to the signal set*/Sigfillset (&act.sa_mask); /*change the action of the specified signal*/         if(0> sigaction (SIGTERM, &act,0) ||0> sigaction (SIGINT, &act,0) ||0> sigaction (SIGUSR1, &act,0) ||0> sigaction (SIGUSR2, &act,0) ||0> sigaction (SIGCHLD, &act,0) ||0> sigaction (sigquit, &act,0) {zlog (Zlog_syserror,"failed to init signals:sigaction ()"); return-1; }         return 0;}

The master process registered Sigterm,sigint,sigusr1,sigusr2,sigchld,sigquit and created Socketpair sp[]. When these signals are received, the master process writes a character representing the signal to sp[1].

[SIGTERM] = ' T ',

[SIGINT] = ' I ',

[SIGUSR1] = ' 1 ',

[SIGUSR2] = ' 2 ',

[Sigquit] = ' Q ',

[SIGCHLD] = ' C '

Sp[0] is the Signal_fd_event event monitoring FD. The callback function of the event reacts differently to different signals (from sp[0] to the characters that represent the signals).

Signal SIGCHLD:

Call Fpm_children_bury (); This function calls Waitpid () to parse the status of the child process and, depending on the circumstances, whether to restart the child process.

Signal SIGINT, SIGTERM:

Call Fpm_pctl (fpm_pctl_state_terminating, fpm_pctl_action_set); Change the status of FPM to terminating

Signal Sigquit

Call Fpm_pctl (fpm_pctl_state_finishing, Fpm_pctl_action_set); Change the status of FPM to finishing

Signal SIGUSR1

Call Fpm_stdio_open_error_log (1) To restart the error log file

Call Fpm_log_open (1) To restart Access log file and restart all child processes

Signal SIGUSR2

Call Fpm_pctl (fpm_pctl_state_reloading, Fpm_pctl_action_set); Change the status of FPM to reloading

Signal processing for child processes

The child process closes the Socketpair and resets the SIGTERM,SIGINT,SIGUSR1,SIGUSR2,SIGHLD to the default action, setting Sigquit to soft quit.

intFpm_signals_init_child ()/* {{{ */{         structSigaction Act, ACT_DFL; memset (&act,0,sizeof(act)); memset (&ACT_DFL,0,sizeof(ACT_DFL)); Act.sa_handler= &Sig_soft_quit; //a signal arrives when the system call or library function is blocked. The system returns an error by default and sets errno to Eintr. Set to auto restart hereAct.sa_flags|=Sa_restart; Act_dfl.sa_handler=SIG_DFL; Close (sp[0]); Close (sp[1]); if(0> sigaction (SIGTERM, &ACT_DFL,0) ||0> sigaction (SIGINT, &ACT_DFL,0) ||0> sigaction (SIGUSR1, &ACT_DFL,0) ||0> sigaction (SIGUSR2, &ACT_DFL,0) ||0> sigaction (SIGCHLD, &ACT_DFL,0) ||0> sigaction (sigquit, &act,0) {zlog (Zlog_syserror,"failed to init child signals:sigaction ()"); return-1;         } zend_signal_init (); return 0;}

One is the readable event queue. The second is the timer queue.

Linux--source code parsing and modeling for PHP-FPM

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.