Nginx / PHP 接口超时机制深度解析
在 Web 开发中,“接口超时”几乎是每个团队都会遇到的问题。
但很多人只会改一个配置:
max_execution_time
结果发现:
👉 还是会超时。
因为真实情况是:
HTTP 请求 = 多层 timeout 叠加
这篇文章将深入讲清:
超时到底发生在哪一层
每个 timeout 的真实作用
Nginx / PHP / PHP-FPM 如何协同
如何正确设计长请求
一、HTTP 请求完整链路
一个 Laravel 接口请求路径:
客户端
↓
负载均衡 / 网关
↓
Nginx
↓
FastCGI
↓
PHP-FPM
↓
Laravel
任何一层 timeout:
👉 都会直接终止请求。
二、PHP 超时机制
1️⃣ max_execution_time
max_execution_time = 60
作用:
PHP 脚本最大执行时间
特点:
只统计 PHP 执行时间
不包含 IO 等待
触发结果:
Fatal error: Maximum execution time exceeded
2️⃣ set_time_limit()
set_time_limit(300);
动态覆盖 php.ini。
常用于:
导出
批量处理
三、PHP-FPM 超时机制
配置:
request_terminate_timeout = 300
作用:
PHP-FPM 强制杀死超时 worker
这是:
服务器级保险机制
即使 PHP 没退出:
👉 FPM 也会终止。
四、Nginx 超时机制(关键)
这是最常被误解的一层。
fastcgi_read_timeout
fastcgi_read_timeout 300;
含义:
Nginx 等待 PHP 响应的最大时间
如果期间:
没有任何数据返回
Nginx 会:
504 Gateway Timeout
proxy_read_timeout
用于反向代理场景。
send_timeout
控制:
客户端读取响应的时间
慢客户端会被断开。
五、Idle Timeout(隐藏杀手)
很多中间层默认认为:
长时间无数据 = 连接异常
结果:
👉 自动断开。
常见位置:
API 客户端
浏览器
网关
负载均衡
六、Laravel 输出缓冲的影响
Laravel 默认:
echo → 缓冲 → 统一返回
导致:
sleep(300);
期间:
👉 Nginx 看不到任何数据。
于是触发:
fastcgi_read_timeout
七、流式输出解决方案
return response()->stream(function () {
for ($i=0;$i<300;$i++) {
echo "tick $i\n";
flush();
sleep(1);
}
});
配合:
fastcgi_buffering off;
实现:
👉 持续输出,避免 idle timeout。
八、模拟慢接口(测试神器)
Route::get('/slow', function () {
while (ob_get_level()) ob_end_clean();
sleep(300);
return 'done';
});
用途:
测试客户端 timeout
验证网关策略
九、为什么不推荐长 HTTP 请求?
风险:
worker 被长期占用
并发下降
容易误判超时
网络中断
十、生产级最佳实践
推荐架构:
HTTP → 队列 → Worker → 状态查询
Laravel:
Queue
Supervisor
Redis
优势:
✅ 稳定
✅ 可扩展
✅ 高并发
十一、调试建议
排查顺序:
客户端 timeout
↓
Nginx timeout
↓
PHP-FPM timeout
↓
PHP timeout
用 curl 验证链路:
curl -v http://api/test
十二、核心结论
接口超时:
不是单点问题
而是链路协同问题
正确理解:
✔ 每层 timeout 含义
✔ 输出缓冲影响
✔ 流式 vs 阻塞请求
才能设计可靠接口。
最终建议
长任务永远不要依赖 HTTP 持续连接。
最佳方案:
异步任务 + 状态查询
这是高并发系统的标准模式。
本作品采用《CC 协议》,转载必须注明作者和本文链接
关于 LearnKu