ホームページ  >  記事  >  バックエンド開発  >  PHP 構成ファイル内のいくつかのタイムアウト構成の簡単な分析

PHP 構成ファイル内のいくつかのタイムアウト構成の簡単な分析

青灯夜游
青灯夜游転載
2022-03-09 11:21:235469ブラウズ

この記事では、PHP 構成ファイルについて説明し、構成ファイル (php.ini および php-fpm.conf) 内のいくつかのタイムアウト関連の構成を分析します。

PHP 構成ファイル内のいくつかのタイムアウト構成の簡単な分析

1. 概要

php.ini と php-fpm.conf にはタイムアウト関連の設定が多数ありますが、これらの設定は正確には何をするのでしょうか?ソースコードではどのように実装されているのでしょうか?この記事では、次のタイムアウト設定について説明します:

php.ini
  • max_execution_time
  • max_input_time
php-fpm.conf
  • process_control_timeout
  • request_terminate_timeout
  • request_slowlog_timeout

##実行環境: Mac 10.14.2 PHP 7.3.7

2. 解析ルールの設定

解析ルール

php.ini の解析は

php_module_startup() ステージで完了し、ini_entry は解析中にあります。 main.c の各 php.ini 設定に対して定義されているルールは、次の形式です。

ZEND_INI_ENTRY3_EX(name, default_value, modifiable, on_modify, arg1, arg2, arg3, displayer)
PHP では、さまざまな種類の設定に対応する多くのマクロが定義されています。

ZEND_INI_ENTRY3_EX は最後のものです。展開後のマクロ (例: PHP_INI_ENTRYMacro

PHP_INI_ENTRY(name, default_value, modifiable, on_modify)
パラメータの説明

name: 設定名

default_value: デフォルト値を設定します

modifiable: 設定の設定可能な範囲

これらのモードは、PHP コマンドがいつ、どこで実行できるかを決定します。設定できます。マニュアルの各指示には、それが属するモードがあります。たとえば、一部のコマンドは ini_set() を使用して PHP スクリプトで設定できますが、その他のコマンドは php.ini または httpd.conf でのみ設定できます。

たとえば、output_buffering ディレクティブは

PHP_INI_PERDIR に属しているため、ini_set() で設定することはできません。ただし、display_errors ディレクティブは PHP_INI_ALL に属しており、ini_set() を含むどこにでも設定できます。

#モード##PHP_INI_USERPHP_INI_PERDIRPHP_INI_SYSTEMPHP_INI_ALL
意味
ユーザー スクリプト (例: ini_set()) または Windows レジストリ (PHP 5.3 以降) および .user.ini で設定できます
php.ini、.htaccess、または httpd.conf で設定できます
で設定できますphp .ini または httpd.conf set
どこにでも設定できます##

on_modify: 配置修改函数

三、max_input_time、max_execution_time

因为max_input_timemax_execution_time 联系比较密切,所以放在一起来讲。

php.ini 解释

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_input_time是每个脚本可以花在解析请求数据上的最大时间。在生产服务器上通过限制max_input_time可以清除掉长时间运行的脚本。在CLI模式下会硬编码为-1,即无限制。

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

翻译:max_execution_time是每个脚本的最大可执行时间。在CLI模式下硬编码为0

配置解析规则

// max_input_time,默认值为无限制
STD_PHP_INI_ENTRY("max_input_time", "-1",    PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateLong, max_input_time, php_core_globals, core_globals)
  
// max_execution_time,默认值为30s,修改函数为OnUpdateTimeout
PHP_INI_ENTRY("max_execution_time", "30",    PHP_INI_ALL, OnUpdateTimeout)

OnUpdateTimeout()函数如下,由第二节可知配置解析发生在php_module_startup()阶段,此时EG(timeout_seconds)被赋值为了max_execution_time,但还没有设置定时器。

// main.c
static PHP_INI_MH(OnUpdateTimeout)
{
    if (stage==PHP_INI_STAGE_STARTUP) {
        /* Don't set a timeout on startup, only per-request */
    /* EG(timeout_seconds) = max_execution_time */
        ZEND_ATOL(EG(timeout_seconds), ZSTR_VAL(new_value));
        return SUCCESS;
    }
    zend_unset_timeout();
    ZEND_ATOL(EG(timeout_seconds), ZSTR_VAL(new_value));
    zend_set_timeout(EG(timeout_seconds), 0);
    return SUCCESS;
}

设置超时定时器

// main.c
int php_request_startup(void) 
{
  ......
  if (PG(max_input_time) == -1) {
    zend_set_timeout(EG(timeout_seconds), 1);
  } else {
  zend_set_timeout(PG(max_input_time), 1);
  }
  ......
}

int php_execute_script(zend_file_handle *primary_file)
{
  ......
    if (PG(max_input_time) != -1) {
    zend_set_timeout(INI_INT("max_execution_time"), 0);
  }  
  ......
}

从上面代码可以看到,如果设置了max_input_time(即值不等于-1,-1可以认为是在CLI模式下),在php_request_startup()阶段会设置一个定时器,超时时间为max_input_time;在php_execute_script()阶段会重新设置一个定时器,超时时间为max_execution_time。那么整个PHP脚本执行的最大执行时间就等于max_input_time + max_execution_time

如果没有设置max_input_time的话(即值等于-1),在php_request_startup()阶段也会设置一个定时器,但超时时间被设为了EG(timeout_seconds),而EG(timeout_seconds)已经在php_module_startup()阶段被赋值为max_execution_time,所以此时的超时时间就是max_execution_time;在php_execute_script()阶段不会重新设置定时器,前一阶段设置的max_execution_time定时器仍然生效着。那么整个PHP脚本的最大执行时间就是max_execution_time
PHP 構成ファイル内のいくつかのタイムアウト構成の簡単な分析

zend_set_time() 使用setitimer(ITIMER_PROF, &t_r, NULL); 来实现定时器,ITIMER_PROF会统计包括用户态和内核态下所花费的时间,而像sleep()这样的系统调用会让进程挂起,不占用cpu时间片,所以这俩超时时间是不包括sleep()时间的。

当定时器到时间后,ZendVM会抛出E_ERROR,即Fatal error错误。

四、process_control_timeout

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

翻译:process_control_timeout是留给子进程处理来自master进程信号的时间限制。

分析

当master进程接收到SIGINTSIGTERMSIGQUITSIGUSR2这些信号时,会调用fpm_pctl()来进行处理。

首先master进程会根据 接收到的信号 和 当前fpm的运行状态 来决定发送给worker进程的是SIGQUIT还是SIGTERM信号,同时注册时间为process_control_timeout的定时事件。

如果在process_control_timeout时间内子进程没有退出,那么master进程会升级SIGQUITSIGTERMSIGTERMSIGKILL,并注册1s的定时事件。SIGKILL就直接终止worker进程了,SIGTERM还能再给worker进程1s的时间。

综上,process_control_timeout可以理解为master进程留给worker进程结束自己的时间,要是到时间worker还没搞定那就开始master自己的策略了。

五、request_terminate_timeout、request_slowlog_timeout

因为request_terminate_timeoutrequest_slowlog_timeout 联系比较密切,所以放在一起来讲。

php-fpm.conf 説明

request_terminate_timeout

; ワーカー プロセスが強制終了されるまでの 1 つのリクエストを処理するためのタイムアウトです。このオプションは次のように指定する必要があります。 'max_execution_time' ini オプション
; が何らかの理由でスクリプトの実行を停止しない場合に使用されます。値 '0' は 'オフ' を意味します。
; 使用可能な単位: s(秒)(デフォルト)、m(分)、h(ours)、または d(ays)
; デフォルト値: 0

翻訳: リクエストを実行するためのタイムアウト期間。その後、ワーカー プロセスは終了します。このオプションは、

max_execution_time this ini オプションが何らかの理由でスクリプトの実行を停止できない場合に使用する必要があります。

request_slowlog_timeout

; 単一リクエストを処理するためのタイムアウト。その後、PHP バックトレースが

; 'slowlog' ファイルにダンプされます。値 '0s' は 'オフ' を意味します。 .
; 使用可能な単位: s(秒)(デフォルト)、m(分)、h(ours)、または d(ays)
; デフォルト値: 0

翻訳: リクエストを実行します。タイムアウトになり、その後 PHP バックトレースがスローログ ファイルに出力されます。

分析

request_slowlog_timeoutrequest_terminate_timeout は、マスター プロセスのハートビート検出 (fpm_pctl_heartbeat()##) で使用されます。 #) 、ハートビート時間 heartbeat 簡略化されたアルゴリズムは

  • request_terminate_timeout

    がオンになっている場合: request_terminate_timeout/1000*3

  • request_terminate_timeout

    が有効になっていない場合: request_slowlog_timeout/1000*3 または 0

  • ##request_terminate_timeout >= request_slowlog_timeout
  • ##3 番目のルールは、slowlog が通常のリクエストに影響を及ぼさないようにすることです。

    heartbeat
  • にはタイムアウト時間の 1 つがかかります。 /3 は、各ハートビート検出がすべてのワーカー プロセスを横断する必要があるため、頻繁すぎるハートビート検出を避けるためのものです。

タイムアウト イベントが発生すると、ワーカー プロセスは直接強制終了され (kill(child_pid, SIGTERM);)、カーネルはリソースをリサイクルして client_socket を閉じ、nginx は次の処理を返します。ブラウザに 502 エラーが送信されます。

推奨学習: 「PHP ビデオ チュートリアル

以上がPHP 構成ファイル内のいくつかのタイムアウト構成の簡単な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。