web-dev-qa-db-ja.com

Proxy enablereuse = onを使用したApache PHP-FPMの奇妙な応答

<Proxy ... enablereuse=on max=10>を有効にすると、奇妙な応答を受け取り始めます。現在のページを更新すると、メインリクエストはさまざまな応答をロードします。空白のページ、別のクライアント向けの応答、または要求されたページのCSSファイルからの404応答のように。

enablereuseを削除すると、奇妙な応答が修正されますが、同じユーザーからの同時リクエストは防止されます。つまり、各リクエストは個別に処理されます。

たとえば、2つのブラウザタブを同じvhostドメインの2つの異なるURLで開くと、最初に要求されたページの読み込みに5秒かかる場合、最初のタブが完了するまで2番目のタブは読み込まれません。

同じクライアントが複数のリクエストを同時に非ブロッキング方式で実行できるようにすることで、これを防止しようとしています。

サーバー環境

CentOS 6.10 x64
php 5.6.37 Remi
Apache 2.4.33 IUS

MPMイベント構成

<IfModule mpm_event_module>
    ServerLimit              100
    StartServers             4
    ThreadLimit              64
    MaxRequestWorkers        100
    MinSpareThreads          25
    MaxSpareThreads          75
    ThreadsPerChild          25
    MaxConnectionsPerChild   1000
    ListenBacklog       511
</IfModule>

仮想ホスト構成(1/4-IPアドレス、UDS、サーバー名を除いてすべて同一)

<VirtualHost 192.168.1.71:443>
    ServerName example.com:443
    DocumentRoot /home/example/example.com
    <IfModule mod_ssl.c>
        SSLEngine on
        SSLCertificateFile /etc/httpd/ssl/certs/example.crt
        SSLCertificateKeyFile /etc/httpd/ssl/private/example.key
        SSLCertificateChainfile /etc/httpd/ssl/certs/example.ca-bundle
        <IfModule mod_setenvif.c>
            SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
        </IfModule>
        <IfModule mod_headers.c>
            Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
        </IfModule>
    </IfModule>
    <Directory "/home/example/example.com">
        AllowOverride All
        Require all granted
    </Directory>
    <IfModule mod_proxy_fcgi.c>
        <FilesMatch \.php$>
            <If "-f %{REQUEST_FILENAME}">
                SetHandler "proxy:unix:/var/run/example.sock|fcgi://127.0.0.1/"
            </If>
        </FilesMatch>
        <Proxy "fcgi://127.0.0.1" enablereuse=on max=10>
            ProxySet timeout=7200
        </Proxy>
    </IfModule>
</VirtualHost>

PHP-FPMプール構成(4つのうち1つはUDSを除いてすべて同一)

[example_com]
user = example
group = example
listen = /var/run/example.sock
listen.owner = example
listen.group = Apache
listen.mode = 0660

pm = dynamic
pm.max_children = 20
pm.start_servers = 2
pm.min_spare_servers = 2
pm.max_spare_servers = 20
pm.max_requests = 1000

security.limit_extensions = .php

UDSがサポートされていない問題についてコメントしている他の投稿があるため、UDSではなくTCPプロキシを使用しようとしましたが、問題は解決しません。

<IfModule mod_proxy_fcgi.c>
    <FilesMatch \.php$>
        <If "-f %{REQUEST_FILENAME}">
            SetHandler "proxy:fcgi://127.0.0.1:9000/"
        </If>
    </FilesMatch>
    <Proxy "fcgi://127.0.0.1:9000" enablereuse=on max=10>
        ProxySet timeout=7200
    </Proxy>
</IfModule>

また、適切なプロセス変更を使用して、pmをdynamicondemand、およびstaticに設定してPHP-FPM構成を変更してみました。


同時リクエストの制限は、PHPセッションと、ファイルシステムベースのセッションに課せられたロックによるものであると判断しました。ただし、この問題は、受け取った奇妙な応答とは一致しません。

3
fyrye

ドキュメントからApache2.4:PHP-FPMなどのFCGIバックエンドへの接続の再利用を有効にする

PHP-FPM(執筆時点では2018年2月)はプリフォークモデルを使用していること、つまり、各ワーカープロセスが一度に1つの接続を処理できることに注意してください。デフォルトでは、mod_proxy(enablereuse = onで構成)は、スレッド化されたmpm(ワーカーやイベントなど)を使用するときに、各httpdプロセスのバックエンドへのThreadsPerChild接続の接続プールを許可するため、次のユースケースを考慮する必要があります。

Under HTTP/1.1 load it will likely cause the creation of up to MaxRequestWorkers connections to the FCGI backend.
Under HTTP/2 load, due to how mod_http2 is implemented, there are additional h2 worker threads that may force the creation of other backend connections. The overall count of connections in the pools may raise to more than MaxRequestWorkers.

PHP-FPMワーカープロセスの最大数は、賢明に構成する必要があります。これは、新しい接続を確立する余地がなく、アイドル状態の持続的接続を処理するためにすべてが「ビジー」になる可能性があるためです。エンドユーザーエクスペリエンスはHTTPリクエストのタイムアウトの山になります。

したがって、私の言及では、mod_proxy_fcgi + php-fpmでenablereuseを使用しないでください。

1
Ivan Gurzhiy