在 Nginx 配置中启用 fastcgi_keep_conn on; 可以让 Nginx 与 PHP-FPM 复用已建立的 FastCGI 连接,减少握手开销。适合高并发场景,但需确保 PHP-FPM 进程数充足,否则可能引发请求排队。
先说结论:开启长连接能降低单次请求延迟,提升单位时间处理能力,但依赖后端进程水位。
- 先定位:确认当前瓶颈在 Nginx 与 PHP-FPM 的连接建立耗时,而非 PHP 代码执行耗时。
- 先做:在 Nginx location 块添加 fastcgi_keep_conn on; 并调整 PHP-FPM pm 参数。
- 再验证:通过压测工具观察请求延迟分布及错误率,公开资料中没有看到可靠的量化数据,需结合实际业务验证。
命令速用版
以下是 Nginx 配置片段,直接放入处理 PHP 请求的 location 块中:
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_keep_conn on;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
}
如果使用 Unix Socket,fastcgi_pass 改为 unix:/path/to/php-fpm.sock。
为什么会这样
启用长连接的核心作用是减少 TCP 握手和 FastCGI 协议初始化的 CPU 开销。默认情况下,Nginx 处理完每个 PHP 请求后会关闭与 PHP-FPM 的连接,高并发时频繁创建销毁连接会消耗大量文件描述符和 CPU 时间。保持连接后,Nginx 可复用空闲连接,降低系统调用频率。
分步处理
按以下步骤操作,每步完成后检查状态再继续:
- 检查当前配置:查看 Nginx 配置中是否已有 fastcgi_keep_conn 指令,确认 PHP-FPM 监听方式(TCP 或 Socket)。
- 调整 PHP-FPM 进程数:编辑 php-fpm.conf 或 pool 配置,确保 pm.max_children 足够大,避免长连接占用导致无空闲进程。适用场景:高并发;风险边界:设置过大会耗尽内存。
- 应用 Nginx 配置:添加指令后执行 nginx -t 检查语法,确认无误后执行 nginx -s reload。
- 监控文件描述符:使用 lsof 或 ss 命令观察 Nginx 与 PHP-FPM 之间的连接状态,确认连接未异常堆积。
怎么验证是否生效
通过日志和监控工具确认连接复用情况及性能变化:
- 检查错误日志:查看 Nginx error.log 是否有 upstream prematurely closed connection 警告,减少此类日志说明连接稳定性提升。
- 观察连接状态:使用命令 ss -anp | grep 9000 查看 TCP 连接状态,TIME_WAIT 数量应相对减少。
- 压测对比:使用 wrk 或 ab 工具在相同并发下对比开启前后的延迟分布,关注 p99 延迟而非仅看平均值。
常见坑
- PHP-FPM 进程不足:如果 pm.max_children 设置过小,长连接会占用空闲进程,导致新请求排队等待,反而降低吞吐量。
- 脚本执行超时:长连接可能掩盖脚本执行慢的问题,需配合 request_terminate_timeout 使用,防止进程被长期占用。
- Socket 权限问题:使用 Unix Socket 时,确保 Nginx 用户有权读写 sock 文件,否则长连接无法建立。
常见问题
使用 Unix Socket 还是 TCP 更好?
同机部署优先选 Unix Socket,开销更低;跨机部署必须用 TCP。长连接对两者均有效,但 Socket 避免了 TCP 协议栈开销。
开启长连接会导致内存泄漏吗?
不会直接导致泄漏,但会占用更多 PHP-FPM 进程驻留内存。需确保 pm.max_requests 设置合理,让进程定期重启释放内存。
Nginx 版本有要求吗?
需要 Nginx 1.1.11 及以上版本支持 fastcgi_keep_conn 指令,旧版本无法配置。
参考来源
- Nginx 官方文档 - ngx_http_fastcgi_module: https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_keep_conn
- PHP 官方手册 - FPM 配置:https://www.php.net/manual/en/install.fpm.configuration.php