There are a lot of timeouts in php.ini and php-fpm.conf, but what exactly do they do? How are they implemented in the source code? This article will talk about the following timeout configurations:
php.ini
- max_execution_time
- max_input_time
php-fpm.conf
- process_control_timeout
- request_terminate_timeout
- request_slowlog_timeout
Configuration resolution rules
Parsing rules
The parsing of php.ini is done in the php_module_startup() phase. ini_entry is a parsing rule defined in main.c for each php.ini configuration, in the following format:
1 |
|
PHP defines many macros for different types of configurations, and ZEND_INI_ENTRY3_EX is the final macro after they are expanded, such as the PHP_INI_ENTRY macro
1 |
|
Parameter explanation
name: Placement Name
default_value: Configure default values
modifiable: The configurable range of the configuration can be set
These modes determine when, where and if a PHP directive can be set. Each directive in the manual has a pattern to which it belongs. For example, some directives can be set in PHP scripts with ini_set(), while others can only be set in php.ini or httpd.conf.
For example, the output_buffering directive is part of PHP_INI_PERDIR and therefore cannot be set with ini_set(). The display_errors directive, however, belongs to PHP_INI_ALL and can be set anywhere, including ini_set().
Mode Meaning PHP_INI_USER Can be set in user scripts (e.g. ini_set()) or in the Windows registry (since PHP 5.3) and in .user.ini PHP_INI_PERDIR can be set in php.ini, .htaccess or httpd.conf PHP_INI_SYSTEM can be set in php.ini or httpd.conf PHP_INI_ALL Can be set anywhere
on_modify: Configuration modification function
max_input_time、max_execution_time
Since max_input_time and max_execution_time are closely related, they are discussed together.
php.ini explained
max_input_time
; Maximum amount of time each script may spend parsing request data. It's a good
; idea to limit this time on productions servers in order to eliminate unexpectedly
; long running scripts.
; Note: This directive is hardcoded to -1 for the CLI SAPI
; http://php.net/max-input-time
max_execution_time
; Maximum execution time of each script, in seconds
; http://php.net/max-execution-...
; Note: This directive is hardcoded to 0 for the CLI SAPI
Configuration resolution rules
1 2 3 4 5 |
|
The OnUpdateTimeout() function is as follows. As you can see from section 2, the configuration resolution occurs during the php_module_startup() phase, when EG(timeout_seconds) is assigned to max_execution_time, but the timer is not yet set.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Set the timeout timer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
As you can see from the above code, if max_input_time is set (i.e. the value is not equal to -1, -1 can be considered in CLI mode), a timer will be set in the php_request_startup() phase with a timeout of max_input_time; in the php_execute_script() phase Then the maximum execution time of the entire PHP script is equal to max_input_time + max_execution_time.
If max_input_time is not set (i.e. the value is equal to -1), a timer is also set in the php_request_startup() phase, but the timeout time is set to EG(timeout_seconds), which is already set in the php_module_ startup() stage is assigned to max_execution_time, so the timeout time is max_execution_time; the timer is not reset in the php_execute_script() stage, and the max_execution_time timer set in the previous stage is still in effect. . Then the maximum execution time of the entire PHP script is max_execution_time.
zend_set_time() uses setitimer(ITIMER_PROF, &t_r, NULL); to implement the timer. ITIMER_PROF will count the time spent in both user state and kernel state, while system calls like sleep() will let the process hang and not take up cpu time slice, so these two timeouts are not include the sleep() time.
When the timer is up, ZendVM will throw an E_ERROR, or Fatal error error.
process_control_timeout
Explanation of php-fpm.conf
; Time limit for child processes to wait for a reaction on signals from master.
; Available units: s(econds), m(inutes), h(ours), or d(ays)
; Default Unit: seconds
When the master process receives SIGINT, SIGTERM, SIGQUIT, SIGUSR2 signals, it will call fpm_pctl() to process them.
First the master process will decide whether to send SIGQUIT or SIGTERM signals to the worker process based on the received signals and the current running status of fpm, and register a timed event with process_control_timeout.
If the child process does not exit within process_control_timeout time, then the master process will upgrade SIGQUIT to SIGTERM, SIGTERM to SIGKILL, and register a 1s timing event. SIGKILL will directly terminate the worker process, and SIGTERM will give the worker process another 1s. The SIGTERM can give the worker process another 1s of time.
In summary, process_control_timeout can be interpreted as the master process to leave the worker process to end their own time, if the time worker is not done then start the master's own strategy.
request_terminate_timeout、request_slowlog_timeout
Since request_terminate_timeout and request_slowlog_timeout are closely related, they are discussed together.
Explanation of php-fpm.conf
request_terminate_timeout
; The timeout for serving a single request after which the worker process will
; be killed. This option should be used when the 'max_execution_time' ini option
; does not stop script execution for some reason. A value of '0' means 'off'.
; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
; Default Value: 0
request_slowlog_timeout
; The timeout for serving a single request after which a PHP backtrace will be
; dumped to the 'slowlog' file. A value of '0s' means 'off'.
; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
; Default Value: 0
Analysis
request_slowlog_timeout and request_terminate_timeout are used in the heartbeat detection of the master process (fpm_pctl_heartbeat()), and the simplified algorithm for heartbeat time heartbeat is
-
With request_terminate_timeout enabled:
request_terminate_timeout/1000*3
-
Without request_terminate_timeout enabled:
request_slowlog_timeout/1000*3
or 0 -
request_terminate_timeout >= request_slowlog_timeout
The third rule is to ensure that slowlog does not affect normal requests, heartbeat takes 1/3 of the timeout time should be to avoid heartbeat detection too often, because each heartbeat detection needs to traverse all worker processes.
If a timeout event occurs, then the worker process will be directly killed, kill(child_pid, SIGTERM);, after which the kernel recovers resources to close the client_socket and nginx returns 502 errors to the browser.