PHP+Docker+Apache部署EC2时POST请求间歇性失败排查求助
问题现象
AWS EC2上部署的容器化应用存在偶发异常:通过POST方式提交表单时,请求会直接中断失败,页面直接展示提交的原始表单数据;Apache日志、PHP应用日志、EC2系统日志中均无对应错误记录,故障无明显触发规律,绝大多数时间服务运行正常。已尝试将EC2实例规格升级为t2.medium、调高PHP的memory_limit参数,问题仍未解决。
当前部署配置
容器编排配置(docker-compose)
services: php: build: ./docker/php restart: always tty: true container_name: php networks: - docker.network ports: - "9000:9000" volumes: apache: build: ./docker/apache restart: always container_name: apache networks: - docker.network depends_on: - php ports: - "80:80" - "443:443" volumes: - .:/var/www/app
基础镜像信息
- PHP服务基础镜像:
php:7.0-fpm-alpine - Apache服务基础镜像:
httpd:2.4-alpine
PHP ini配置参数
allow_url_fopen = On allow_url_include = Off asp_tags = Off display_errors = On display_startup_errors = On error_reporting = E_ALL enable_dl = Off file_uploads = On max_execution_time = 300 max_input_time = 60 max_input_vars = 100000 memory_limit = 3000M session.gc_maxlifetime = 1440 upload_max_filesize = 250M post_max_size = 500M max_file_uploads = 50 date.timezone = Europe/London
Apache FCGI转发规则
PHP请求通过如下规则转发至PHP-FPM服务:
ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://php:9000${DOCUMENT_ROOT}/$1
排查方向与解决建议
- 优先修复Apache FCGI代理配置缺陷:当前使用的
ProxyPassMatch规则未配置FCGI连接复用相关参数,是该故障的最高概率诱因。httpd 2.4的mod_proxy_fcgi模块默认会复用FCGI长连接,当PHP-FPM侧已经主动回收关闭空闲连接、但Apache侧仍持有该连接的引用时,新的POST请求打到这个失效连接上,会直接中断请求、原样返回POST表单数据,整个过程不会触发PHP脚本执行,因此PHP、Apache业务日志、系统日志都不会记录错误。在转发规则末尾追加参数即可修复:
ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://php:9000${DOCUMENT_ROOT}/$1 disablereuse=On timeout=60 enablereuse=Off
- 对齐PHP-FPM与Apache的超时配置:进入PHP容器编辑
/usr/local/etc/php-fpm.d/www.conf,将pm.process_idle_timeout设置为10s,确保FPM回收空闲进程的时间短于Apache代理的空闲连接超时时间,避免Apache拿到已被FPM关闭的死连接;同时根据业务并发量适当调大pm.max_children数值,避免偶发请求高峰时FPM进程占满导致连接被直接拒绝。 - 补全全链路日志配置:当前配置缺少PHP-FPM层的访问日志、慢日志,也没有开启Apache代理模块的调试日志,无法追踪请求是否到达FPM层。临时调整Apache全局日志级别为
LogLevel proxy:trace2 proxy_fcgi:trace2,在PHP-FPM配置中开启访问日志、设置request_slowlog_timeout = 5s开启慢日志,复现故障时可直接定位请求中断的节点。 - 移除PHP-FPM不必要的端口映射:当前docker-compose配置将PHP容器的9000端口直接映射到EC2主机公网,公网扫描流量、恶意请求可能直接打满FPM连接池,触发偶发连接异常。同自定义docker网络内的Apache服务可直接通过容器名
php解析访问9000端口,不需要将该端口映射到主机,直接删除php服务下的ports配置段即可。 - 对齐Apache与PHP的请求大小限制:当前仅在PHP侧配置了
post_max_size = 500M,Apache侧默认LimitRequestBody配置在部分编译版本中存在阈值边界bug,偶发接近大小阈值的POST请求会被代理层直接拦截返回原始内容。在Apache站点配置中添加LimitRequestBody 524288000(即500M),和PHP侧配置保持一致。 - 排查Docker网桥偶发连接异常:若上述配置修改后问题仍存在,可在Apache、PHP两个容器内分别安装tcpdump工具,针对9000端口的TCP流量抓包,故障复现时核对TCP流中是否存在RST包,确认是否为docker0网桥在高并发下的偶发连接中断问题。
内容的提问来源于stack exchange,提问作者Rob H
相关产品推荐
相关产品推荐

