Nginx与PHP-FPM的连接超时配置:解决高并发下的504 Gateway Timeout问题
各位朋友,大家好。今天我们来聊聊在高并发场景下,Nginx 与 PHP-FPM 如何配置连接超时,以及如何避免常见的 504 Gateway Timeout 错误。504 错误往往是系统瓶颈的直接体现,也是我们优化性能的关键入口。
一、504 Gateway Timeout 错误产生的根本原因
504 Gateway Timeout 错误,顾名思义,是指 Nginx 作为网关,向上游服务器(通常是 PHP-FPM)发送请求后,在规定的时间内没有收到响应,从而返回给客户端的错误。其本质是:Nginx 认为 PHP-FPM 服务处理请求超时了。
造成超时的原因有很多,可以简单归纳为以下几类:
- PHP-FPM 处理请求缓慢: 这是最常见的原因。可能是 PHP 代码本身效率低下,执行了大量耗时操作(如复杂的数据库查询、大文件读写、远程 API 调用等)。也可能是 PHP-FPM 服务器资源不足(CPU、内存),导致处理能力下降。
- Nginx 与 PHP-FPM 之间的网络问题: 尽管通常它们部署在同一台服务器上,但网络连接仍然可能存在问题,例如网络拥塞、丢包等。
- PHP-FPM 进程池拥堵: PHP-FPM 的进程池如果已经全部被占用,新的请求只能排队等待,如果等待时间超过 Nginx 的超时设置,就会返回 504 错误。
- Nginx 超时配置不合理: Nginx 的超时设置过短,即使 PHP-FPM 能够正常处理请求,但如果处理时间略长,仍然可能被 Nginx 判定为超时。
- PHP-FPM 本身故障: PHP-FPM 进程崩溃、挂起等异常情况也会导致 Nginx 收不到响应。
二、Nginx 中与 PHP-FPM 连接相关的超时配置项
Nginx 与 PHP-FPM 通信通常使用 FastCGI 协议。因此,我们需要关注与 FastCGI 相关的超时配置项。这些配置项主要位于 http, server, location 块中,作用范围依次递减。
以下是几个关键的配置项:
-
fastcgi_connect_timeout: Nginx 尝试连接到 PHP-FPM 服务器的超时时间。如果在这个时间内无法建立连接,Nginx 将返回错误。- 默认值:
60s - 建议:根据实际网络环境调整。如果 PHP-FPM 服务器负载较高或网络不稳定,可以适当增加该值。
- 默认值:
-
fastcgi_send_timeout: Nginx 向 PHP-FPM 服务器发送请求的超时时间。如果在这个时间内无法将完整的请求发送完毕,Nginx 将中断连接。- 默认值:
60s - 建议:一般情况下,请求体不会太大,默认值即可。如果需要上传大文件,则需要适当增加。
- 默认值:
-
fastcgi_read_timeout: Nginx 等待 PHP-FPM 服务器响应的超时时间。这是最关键的配置项,直接影响 504 错误。如果在这个时间内没有收到 PHP-FPM 的响应,Nginx 将返回 504 Gateway Timeout 错误。- 默认值:
60s - 建议:需要根据 PHP 脚本的执行时间进行调整。对于执行时间较长的脚本,应该适当增加该值。
- 默认值:
-
fastcgi_buffers: 用于读取 PHP-FPM 响应的缓冲区数量和大小。- 默认值:
8 4k|8 8k - 建议:如果 PHP-FPM 返回较大的响应头或内容,需要适当增加缓冲区大小。
- 默认值:
-
fastcgi_buffer_size: 用于读取 PHP-FPM 响应的第一行数据的缓冲区大小,例如状态行和响应头。- 默认值:
4k|8k - 建议:如果 PHP-FPM 返回较大的响应头,需要适当增加缓冲区大小。
- 默认值:
-
fastcgi_busy_buffers_size: 当 busy buffer 超过此值时,nginx 不会再从 fastcgi 读取新的数据,直到 busy buffer 降到此值以下。- 默认值:
8k|16k - 建议:需要大于
fastcgi_buffer_size,否则可能出现缓冲区溢出。
- 默认值:
-
fastcgi_temp_file_write_size: 写入临时文件的缓冲区大小。当响应数据大于fastcgi_buffers * fastcgi_buffer_size时,Nginx 会将响应数据写入临时文件。- 默认值:
8k|16k - 建议:一般情况下,默认值即可。如果响应数据非常大,可以适当增加。
- 默认值:
-
fastcgi_temp_path: 临时文件存储目录。- 默认值:由 Nginx 配置文件中的
client_body_temp_path指令决定。 - 建议:选择一个拥有足够空间且速度较快的磁盘。
- 默认值:由 Nginx 配置文件中的
三、PHP-FPM 相关配置项
除了 Nginx 的配置,PHP-FPM 也有一些相关的配置项需要关注,主要位于 php-fpm.conf 或相关 pool 配置文件中。
-
request_terminate_timeout: PHP 脚本的最大执行时间。如果脚本执行时间超过此值,PHP-FPM 将强制终止该脚本。- 默认值:
0(表示永不超时) - 建议:不建议设置为 0,应该根据实际情况设置一个合理的超时时间,避免恶意脚本占用资源。 需要注意的是,该值应该小于 Nginx 的
fastcgi_read_timeout,否则即使 PHP-FPM 终止了脚本,Nginx 仍然会等待超时。
- 默认值:
-
request_slowlog_timeout: 当 PHP 脚本执行时间超过此值时,PHP-FPM 将记录一条慢日志。- 默认值:
0(表示不记录慢日志) - 建议:建议设置一个合理的超时时间,方便定位性能瓶颈。
- 默认值:
-
slowlog: 慢日志的存储路径。- 默认值:未设置
- 建议:指定一个合适的存储路径,方便分析慢日志。
-
pm: 进程管理方式。- 可选值:
static,dynamic,ondemand - 建议:在高并发场景下,建议使用
dynamic或ondemand,可以根据实际负载动态调整进程数量。
- 可选值:
-
pm.max_children: 最大子进程数量。- 默认值:取决于系统资源
- 建议:根据系统资源和并发量进行调整。过小的
pm.max_children可能导致进程池拥堵,过大的pm.max_children可能导致系统资源耗尽。
-
pm.start_servers: 启动时创建的子进程数量。- 默认值:取决于系统资源
- 建议:根据实际负载进行调整。
-
pm.min_spare_servers: 空闲子进程的最小数量。- 默认值:取决于系统资源
- 建议:根据实际负载进行调整。
-
pm.max_spare_servers: 空闲子进程的最大数量。- 默认值:取决于系统资源
- 建议:根据实际负载进行调整。
四、配置示例
以下是一个 Nginx 和 PHP-FPM 的配置示例,用于处理高并发场景下的超时问题。
Nginx 配置 (nginx.conf):
http {
# ... 其他配置 ...
fastcgi_connect_timeout 30s;
fastcgi_send_timeout 30s;
fastcgi_read_timeout 120s; # 关键:增加读取超时时间
fastcgi_buffers 16 8k;
fastcgi_buffer_size 16k;
fastcgi_busy_buffers_size 32k;
server {
# ... 其他配置 ...
location ~ .php$ {
# ... 其他配置 ...
fastcgi_pass unix:/run/php/php7.4-fpm.sock; # 根据实际情况修改
fastcgi_index index.php;
include fastcgi.conf;
}
}
}
PHP-FPM 配置 (php-fpm.conf 或 pool 配置文件):
[www] ; pool name
listen = /run/php/php7.4-fpm.sock ; 根据实际情况修改
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 50 ; 根据系统资源调整
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
request_terminate_timeout = 90s ; 关键:设置脚本最大执行时间,小于 Nginx 的 fastcgi_read_timeout
request_slowlog_timeout = 10s
slowlog = /var/log/php7.4-fpm.log ; 根据实际情况修改
五、排查与优化步骤
如果仍然出现 504 Gateway Timeout 错误,可以按照以下步骤进行排查和优化:
-
检查 Nginx 错误日志 (error.log): Nginx 错误日志会记录 504 错误以及其他相关信息,例如连接错误、超时错误等。
-
检查 PHP-FPM 日志 (error.log 和 slowlog): PHP-FPM 错误日志会记录 PHP 脚本的错误信息,慢日志会记录执行时间超过
request_slowlog_timeout的脚本。 -
检查系统资源 (CPU、内存、磁盘 I/O): 使用
top,free,iostat等命令检查服务器的 CPU、内存、磁盘 I/O 使用情况,判断是否存在资源瓶颈。 -
优化 PHP 代码: 使用性能分析工具 (例如 Xdebug) 分析 PHP 代码,找出性能瓶颈,并进行优化。可以考虑以下几个方面:
- 减少数据库查询次数和数据量。
- 使用缓存 (例如 Memcached, Redis) 缓存热点数据。
- 优化算法和数据结构。
- 避免阻塞操作 (例如同步 I/O)。
-
调整 Nginx 和 PHP-FPM 配置: 根据实际情况调整 Nginx 和 PHP-FPM 的超时时间、缓冲区大小、进程管理方式等配置项。
-
增加 PHP-FPM 进程数量: 如果 CPU 负载不高,可以适当增加
pm.max_children,以提高并发处理能力。 -
优化数据库: 如果数据库是瓶颈,可以考虑以下几个方面:
- 优化 SQL 查询。
- 添加索引。
- 使用数据库连接池。
- 升级数据库服务器。
- 使用读写分离。
-
使用 CDN: 使用 CDN 可以缓存静态资源,减轻服务器的负载。
-
负载均衡: 使用负载均衡可以将请求分发到多台服务器上,提高系统的整体处理能力。
六、一些需要注意的点
- 超时时间设置要合理: 超时时间设置过短可能导致误判,超时时间设置过长则会浪费资源。需要根据实际情况进行权衡。
- 监控与告警: 建立完善的监控与告警系统,及时发现和解决问题。
- 压力测试: 在生产环境上线之前,进行充分的压力测试,模拟高并发场景,找出潜在的瓶颈。
- 逐步调整: 修改配置后,逐步进行测试,避免一次性修改过多配置导致问题难以定位。
七、代码示例:模拟耗时操作
为了演示超时配置的效果,我们可以创建一个简单的 PHP 脚本,模拟耗时操作。
<?php
// 模拟耗时操作
sleep(rand(5, 15)); // 随机睡眠 5 到 15 秒
echo "Hello, world!";
?>
将该脚本部署到 PHP-FPM 服务器上,并使用 Nginx 访问。然后,可以逐步调整 Nginx 和 PHP-FPM 的超时配置,观察 504 错误的变化。
八、表格:常用配置项及其建议值
| 配置项 | 位置 | 默认值 | 建议值 | 说明 |
|---|---|---|---|---|
fastcgi_connect_timeout |
http, server, location |
60s |
30s – 60s (根据网络环境调整) |
Nginx 连接 PHP-FPM 的超时时间。 |
fastcgi_send_timeout |
http, server, location |
60s |
30s – 60s (一般情况下足够) |
Nginx 发送请求到 PHP-FPM 的超时时间。 |
fastcgi_read_timeout |
http, server, location |
60s |
90s – 180s (根据 PHP 脚本执行时间调整) |
Nginx 等待 PHP-FPM 响应的超时时间。 关键配置,直接影响 504 错误。 |
fastcgi_buffers |
http, server, location |
8 4k|8 8k |
8 8k – 16 8k (根据 PHP-FPM 返回内容大小调整) |
用于读取 PHP-FPM 响应的缓冲区数量和大小。 |
fastcgi_buffer_size |
http, server, location |
4k|8k |
8k – 16k (根据 PHP-FPM 返回的响应头大小调整) |
用于读取 PHP-FPM 响应的第一行数据的缓冲区大小。 |
fastcgi_busy_buffers_size |
http, server, location |
8k|16k |
16k – 32k (需要大于 fastcgi_buffer_size) |
当 busy buffer 超过此值时,nginx 不会再从 fastcgi 读取新的数据,直到 busy buffer 降到此值以下。 |
request_terminate_timeout |
php-fpm.conf |
0 (永不超时) |
60s – 120s (必须小于 Nginx 的 fastcgi_read_timeout) |
PHP 脚本的最大执行时间。 关键配置,防止恶意脚本占用资源。 |
request_slowlog_timeout |
php-fpm.conf |
0 (不记录) |
5s – 15s (根据实际情况调整) |
当 PHP 脚本执行时间超过此值时,PHP-FPM 将记录一条慢日志。 |
pm |
php-fpm.conf |
static |
dynamic 或 ondemand (高并发场景推荐) |
进程管理方式。 dynamic:动态调整进程数量; ondemand:按需创建进程。 |
pm.max_children |
php-fpm.conf |
取决于系统资源 | 根据系统资源和并发量调整 (例如 30 – 80) |
最大子进程数量。 |
九、总结:优化配置,避免超时
解决 Nginx 与 PHP-FPM 的 504 Gateway Timeout 问题,需要综合考虑 Nginx 和 PHP-FPM 的配置,以及 PHP 代码本身的性能。合理的超时配置、充足的系统资源、优化的代码是解决问题的关键。通过监控日志、分析性能瓶颈,可以逐步优化系统,提高在高并发场景下的稳定性。