Apache PHP-FPM 代理启用重用 = on 时出现奇怪的响应

Wil*_* B. 6 php-fpm apache-2.4 mod-proxy-fcgi

启用后<Proxy ... enablereuse=on max=10>我开始收到奇怪的响应。刷新当前页面时,主请求加载不同的响应;例如空白页面、针对单独客户端的响应或来自请求页面上 CSS 文件的 404 响应。

删除enablereuse,修复了奇怪的响应,但阻止了来自同一用户的并发请求,这意味着每个请求都是单独提供的。

例如:在同一虚拟主机域上打开两个不同 URL 的浏览器选项卡,如果第一个请求的页面需要 5 秒才能加载,则在第一个选项卡完成之前不会加载第二个选项卡。

我试图通过允许同一客户端以并发非阻塞方式同时执行多个请求来防止这种情况。

服务器环境

CentOS 6.10 x64
php 5.6.37 Remi
Apache 2.4.33 IUS
Run Code Online (Sandbox Code Playgroud)

MPM 事件配置

<IfModule mpm_event_module>
    ServerLimit              100
    StartServers             4
    ThreadLimit              64
    MaxRequestWorkers        100
    MinSpareThreads          25
    MaxSpareThreads          75
    ThreadsPerChild          25
    MaxConnectionsPerChild   1000
    ListenBacklog       511
</IfModule>
Run Code Online (Sandbox Code Playgroud)

虚拟主机配置(4 中的 1 - 除 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>
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

由于其他帖子评论了不支持 UDS 的问题,我尝试使用 TCP 代理而不是 UDS,但问题仍然存在:

<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>
Run Code Online (Sandbox Code Playgroud)

还尝试更改 PHP-FPM 配置,将 pm 设置为dynamicondemandstatic进行适当的流程更改。


我确定并发请求的限制是由于 PHP 会话和基于文件系统的会话施加的锁定造成的。然而,这个问题与我收到的奇怪回复并不相符。

小智 1

来自文档 Apache 2.4:启用与 PHP-FPM 等 FCGI 后端的连接重用

请记住,PHP-FPM(截至撰写本文时,2018 年 2 月)使用预分叉模型,即其每个工作进程同时可以处理一个连接。默认情况下,mod_proxy(使用enablereuse=on配置)允许在使用线程化mpm(如worker或event)时将ThreadsPerChild连接池连接到每个httpd进程的后端,因此应考虑以下用例:

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.
Run Code Online (Sandbox Code Playgroud)

需要明智地配置 PHP-FPM 工作进程的最大数量,因为它们有可能最终都“忙于”处理空闲的持久连接,而没有任何空间建立新的连接,并且最终用户体验将受到影响。是一堆 HTTP 请求超时。

所以我提到不要将enablereuse与mod_proxy_fcgi + php-fpm一起使用。