关于Nginx中的各种timeout设置
很多人第一次看 Nginx 配置里的各种 timeout,会有一种错觉:
- 好像都是“超时时间”
- 名字只差一个单词
- 调大一点似乎总没坏处
结果线上一出问题,大家就开始机械地把 60s 改成 600s,然后继续观察。
这类处理方式通常不太可靠。因为 Nginx 里的 timeout 并不是一个参数的不同别名,而是分布在不同阶段、不同方向、不同对象上的控制开关。你如果没搞清楚“是谁在等谁”“在等什么”“是总时长还是两次读写之间的空档”,调出来的值往往既不能解决问题,还可能把连接、内存和文件描述符长期占住。
这篇文章就专门把这个问题讲透。我们会从 Nginx 请求链路入手,系统梳理:
- 客户端到 Nginx 的 timeout
- Nginx 到上游服务的 timeout
- 长连接与 keepalive 的 timeout
- DNS 解析相关的 timeout
- 常见报错码背后通常是哪一类 timeout
- 上传、大响应、长轮询、WebSocket 等场景应该怎么配
读完后,你至少应该能回答三个关键问题:
- 为什么
proxy_read_timeout 300s也不一定能撑住一个 10 分钟请求 - 为什么上传大文件时,真正关键的可能不是
proxy_read_timeout - 为什么 timeout 调大,未必是稳定性更高,反而可能更差
1. 先建立一个最重要的心智模型
先说结论:
Nginx 中大多数 timeout,控制的不是“整个请求最多跑多久”,而是“某一次 I/O 操作之间允许空闲多久”。
这句话非常关键。
很多人以为:
proxy_read_timeout 60s;
表示“后端接口必须在 60 秒内全部返回完”。
这并不准确。
它更接近下面这个意思:
Nginx 在向上游读取响应时,如果连续 60 秒都没有读到任何新数据,就判定超时。
也就是说:
- 如果后端每隔 30 秒吐一个字节,理论上连接可以一直活着
- 如果后端前 59 秒完全没返回,第 60 秒前刚好返回一点数据,计时又会重新开始
- 真正决定“请求总耗时”的,往往不是单个 timeout,而是整条链路上多个组件共同作用的结果
所以要理解 Nginx timeout,不能只盯参数名字,而要先看整个链路。
1.1 一个 HTTP 请求会经过哪些等待阶段
假设 Nginx 做反向代理,一个请求通常会经历这些阶段:
- 客户端和 Nginx 建立连接
- 客户端把请求头发给 Nginx
- 客户端把请求体发给 Nginx
- Nginx 和上游服务建立连接
- Nginx 把请求转发给上游服务
- Nginx 等上游服务返回响应
- Nginx 把响应发回客户端
- 请求结束后,连接可能继续 keepalive,也可能关闭
你会发现,不同 timeout 管的是不同阶段:
client_header_timeout管第 2 步client_body_timeout管第 3 步proxy_connect_timeout管第 4 步proxy_send_timeout管第 5 步proxy_read_timeout管第 6 步send_timeout管第 7 步keepalive_timeout管第 8 步
这就是理解它们差异的主线。
2. 客户端到 Nginx:请求接收阶段的 timeout
先看客户端这一侧,也就是“浏览器或调用方把请求交给 Nginx”这部分。
2.1 client_header_timeout
client_header_timeout 10s;
它控制的是:Nginx 等待客户端把完整请求头发送完的时间。
如果客户端连请求头都迟迟发不完,Nginx 会返回 408 Request Timeout。
这个参数主要用来防御两类问题:
- 非常慢的客户端
- 故意拖住连接、缓慢发送请求头的攻击行为,比如 Slowloris
什么时候要关注它
大多数普通业务里,请求头本来就很小,所以它通常不是性能瓶颈,而是安全和资源保护参数。
比较常见的建议是:
- 公网入口不要配得太大
- 内网高信任环境可以适当放宽
- 如果遭遇慢请求头攻击,要结合连接数限制一起看,而不是只改 timeout
2.2 client_body_timeout
client_body_timeout 30s;
它控制的是:Nginx 在读取客户端请求体时,两次读操作之间允许空闲多久。
这个参数最常见于:
- 文件上传
- 大 JSON / 表单提交
- 客户端网络很慢的移动端场景
这里最容易产生误解。
它不是说“文件上传总时长不能超过 30 秒”,而是说:
在上传过程中,如果客户端连续 30 秒都没有继续发送任何请求体数据,Nginx 才判定超时。
所以一个 2GB 文件,只要客户端一直稳定地往前传,即使总耗时远大于 30 秒,也不一定超时。
它和 client_max_body_size 不是一回事
很多人会把这两个配置混在一起:
client_max_body_size 100m;
client_body_timeout 30s;
它们控制的是两个完全不同的问题:
client_max_body_size限制“能不能上传这么大”client_body_timeout限制“上传过程中能不能长时间不发数据”
前者触发通常是 413 Request Entity Too Large,后者触发通常是 408 Request Timeout。
2.3 keepalive_timeout
keepalive_timeout 65s;
它控制的是:客户端和 Nginx 之间的 HTTP keepalive 空闲连接,可以保留多久。
注意,这不是“单个请求执行多久”,而是“请求已经结束后,这个 TCP 连接还能空闲等下一次请求多久”。
作用非常直接:
- 配得大一点,可以减少重复建连成本
- 配得太大,会让大量空闲连接占住文件描述符和内存
- 配得太小,短连接变多,握手开销上升
公网 Web 服务一般会在“减少建连开销”和“控制空闲连接资源”之间取平衡,通常不会无限放大。
2.4 send_timeout
send_timeout 60s;
它控制的是:Nginx 向客户端发送响应时,两次写操作之间允许空闲多久。
这个参数经常被误解成“整个响应必须在 60 秒内发完”,其实也不是。
更准确地说:
如果客户端接收能力太差,导致 Nginx 连续一段时间都无法继续把数据写出去,才会触发
send_timeout。
所以它主要针对的是“慢下载客户端”,不是“后端处理太慢”。
典型场景
- 客户端网络很差,下载大文件特别慢
- 某些恶意客户端故意维持低速读取,占住服务器连接
- 大量长时间慢速下行,拖垮 worker 资源
如果你的问题是“后端接口响应太慢”,调 send_timeout 通常没有意义,因为它管的是下行发送,不是上游处理。
3. Nginx 到上游服务:反向代理阶段的 timeout
这部分是大家最常改、也最容易改错的地方。
假设你有这样的配置:
location /api/ {
proxy_pass http://backend;
}
这时最核心的三个 timeout 是:
proxy_connect_timeoutproxy_send_timeoutproxy_read_timeout
3.1 proxy_connect_timeout
proxy_connect_timeout 3s;
它控制的是:Nginx 与上游建立 TCP 连接最多等多久。
这个阶段还没有开始发业务请求,纯粹是在连后端。
如果这里超时,常见表现通常是:
- 上游实例挂了
- 网络不通
- SYN 建连迟迟得不到响应
- 上游监听端口异常
这类问题更偏基础设施或网络连通性,通常不是业务代码执行慢。
配置思路
proxy_connect_timeout 通常不建议很大。
原因很简单:
- 连不上就是连不上
- 如果连接阶段都要等很久,问题往往不在“多给几秒”能解决
- 等太久只会让故障扩散得更慢、积压得更多
在很多生产环境里,连接超时常常会配得比读取超时短得多。
3.2 proxy_send_timeout
proxy_send_timeout 30s;
它控制的是:Nginx 向上游发送请求时,两次写操作之间允许空闲多久。
注意,它不是“整个请求必须 30 秒内发给上游”,而是发送过程中不能长时间卡住。
这个参数常见于:
- 请求体很大,需要转发上传给后端
- 上游接收能力弱,socket 缓冲区迟迟消化不掉
- 请求流式转发到后端
如果你做的是大文件上传到应用服务器,这个参数就比很多人想象中更重要。
3.3 proxy_read_timeout
proxy_read_timeout 60s;
它控制的是:Nginx 读取上游响应时,两次读操作之间允许空闲多久。
这是最常见、也最容易被滥用的参数。
很多人遇到 504 Gateway Timeout,第一反应就是把它调大。这个动作有时有效,但你必须先想清楚:
- 上游是真的正常,只是业务确实耗时长
- 还是上游卡死、线程池耗尽、数据库锁等待、外部依赖超时
如果是第 2 种,单纯调大只是在把坏请求留得更久。
一个特别重要的细节
proxy_read_timeout 控制的是“读响应期间的空闲间隔”,不是总耗时上限。
举个例子:
- 一个 SSE 接口每 15 秒发一条事件
- 你配了
proxy_read_timeout 60s
那么这个连接完全可以长时间保持,因为每次事件都会刷新读超时计时器。
反过来:
- 一个后端接口需要先计算 70 秒
- 这 70 秒里一字节都不返回
- 你配了
proxy_read_timeout 60s
那它就会在 60 秒左右超时,即使后端第 61 秒已经快算完了。
这也是为什么“长任务接口”有时应该改成异步任务加轮询,而不是无脑把 proxy_read_timeout 调到几百秒。
4. FastCGI、uWSGI、SCGI:只是协议不同,思路完全一样
如果你的 Nginx 后面不是普通 HTTP 服务,而是 PHP-FPM、uWSGI 或 SCGI,那么参数名会变成:
fastcgi_connect_timeoutfastcgi_send_timeoutfastcgi_read_timeoutuwsgi_connect_timeoutuwsgi_send_timeoutuwsgi_read_timeoutscgi_connect_timeoutscgi_send_timeoutscgi_read_timeout
它们本质上只是把 proxy_* 的语义映射到不同上游协议:
*_connect_timeout管连接建立*_send_timeout管请求发送*_read_timeout管响应读取
所以如果你理解了 proxy_* 三件套,这一组参数并没有新的心智负担。
5. DNS 解析:resolver_timeout 是什么
resolver 10.0.0.2 valid=30s;
resolver_timeout 5s;
resolver_timeout 控制的是:Nginx 向 DNS 解析器发起查询后,最多等多久。
这个参数常见于:
proxy_pass使用域名- 上游地址需要动态解析
- 容器、Kubernetes、Service Mesh 等环境里依赖内部 DNS
如果 DNS 解析慢或者不稳定,你会看到一种很迷惑的现象:
- 后端服务其实活着
- 但 Nginx 还是访问失败
- 问题根源不是应用,而是解析不到地址
在这种场景里,盯着 proxy_read_timeout 是没用的,因为请求连真正的上游都还没找到。
6. 把这些 timeout 按“方向”和“阶段”记住
如果你总记不住这些名字,可以用下面这个方式强行分类。
6.1 客户端到 Nginx
client_header_timeout:客户端发请求头太慢client_body_timeout:客户端发请求体太慢send_timeout:客户端收响应太慢keepalive_timeout:请求结束后,客户端空闲连接保留多久
6.2 Nginx 到上游
proxy_connect_timeout:连上游太慢proxy_send_timeout:给上游发请求太慢proxy_read_timeout:等上游回响应太慢
6.3 名字相同但对象不同
最容易混淆的是下面两组:
send_timeout是 Nginx 发给客户端proxy_send_timeout是 Nginx 发给上游
还有:
client_body_timeout是 Nginx 收客户端请求体proxy_read_timeout是 Nginx 收上游响应体
你只要把 Nginx 想成中间人,这些方向关系一下就清楚了。
7. 常见状态码和日志,通常在暗示什么
timeout 真正难的地方,不是名字,而是线上出问题时该先怀疑谁。
7.1 408 Request Timeout
通常意味着客户端在向 Nginx 发送请求头或请求体时太慢。
优先排查:
client_header_timeoutclient_body_timeout- 是否有异常慢客户端或攻击流量
7.2 413 Request Entity Too Large
这不是 timeout,而是体积限制问题。
优先排查:
client_max_body_size- 上传接口是否需要单独放宽
7.3 499 Client Closed Request
这是 Nginx 非常有代表性的一个状态码,表示:客户端先断开了连接。
典型场景:
- 前端等待太久,用户刷新页面了
- 调用方自己的超时比 Nginx 更短
- 上游处理太慢,用户提前放弃
这时你不能只盯 Nginx,要把客户端、网关、上游应用的超时一起看。
7.4 502 Bad Gateway
常见于:
proxy_connect_timeout失败- 上游进程异常退出
- 上游协议不匹配
- DNS 解析失败
它并不一定意味着“上游处理超时”,也可能是压根没连上。
7.5 504 Gateway Timeout
这是最典型的“上游等待超时”信号。
优先排查:
proxy_read_timeout- 上游线程池、连接池是否耗尽
- 数据库慢 SQL、锁等待、下游依赖超时
- 是否需要改成异步任务
一个原则:
504 往往只是症状,根因通常在更后面的服务。
8. 几类特别常见的业务场景,应该怎么配
参数本身不难,难的是落到场景。
8.1 普通 Web API
比如后台管理、用户中心、CRUD 接口。
这类接口的特征通常是:
- 请求体不大
- 响应时间预期比较短
- 超时太长反而会掩盖问题
一个常见思路是:
location /api/ {
proxy_connect_timeout 3s;
proxy_send_timeout 15s;
proxy_read_timeout 30s;
send_timeout 30s;
proxy_pass http://backend;
}
这种配置背后的思路不是“绝对正确”,而是:
- 连接建立要快失败
- 正常业务请求不应该无限慢
- 出现异常时尽早暴露,而不是把请求挂很久
8.2 文件上传接口
文件上传最容易配错,因为很多人只改 proxy_read_timeout。
实际上更关键的通常是:
client_max_body_sizeclient_body_timeoutproxy_send_timeout
如果上传要先经过 Nginx 再到后端,可以参考这种思路:
location /upload/ {
client_max_body_size 500m;
client_body_timeout 120s;
proxy_connect_timeout 3s;
proxy_send_timeout 120s;
proxy_read_timeout 60s;
proxy_pass http://backend;
}
这里的逻辑是:
- 允许较大体积
- 允许较慢但持续的上传
- 给 Nginx 往上游传请求体足够时间
- 上游处理完成后的等待时间另算
8.3 长轮询、SSE、流式输出
这类请求和普通 API 最大的区别是:
- 连接会持续很久
- 但只要周期性有数据流动,未必算超时
比如 SSE:
location /events/ {
proxy_connect_timeout 3s;
proxy_read_timeout 1h;
proxy_send_timeout 1h;
proxy_buffering off;
proxy_pass http://backend;
}
这里重点不是单纯把 timeout 调大,而是你要明确:
- 上游是否会定期发送心跳
- 中间链路是否还有其他更短的超时
- 是否需要关闭缓冲,避免流式响应被攒住
如果后端 10 分钟完全不发任何字节,那么就算你以为它在“流式处理”,实际上对 proxy_read_timeout 来说,依然只是长时间沉默。
8.4 WebSocket
WebSocket 升级成功后,本质上是长连接。
比较常见的思路是:
location /ws/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 1h;
proxy_send_timeout 1h;
proxy_pass http://backend;
}
这里你真正要关心的是:
- 应用层是否有 ping/pong 或心跳
- 中间网关、LB、云厂商连接超时是多少
- 断连重连策略是否健全
因为很多时候,断开连接的并不是 Nginx,而是更前面一层的负载均衡。
8.5 大文件下载
如果你的用户要通过 Nginx 下载很大的文件,重点通常不在 proxy_read_timeout,而在:
send_timeout- 是否支持断点续传
- 是否由 Nginx 直接回源静态文件
- 客户端网络质量是否足够稳定
如果客户端接收很慢,Nginx 迟迟发不出去,send_timeout 就可能触发。
9. timeout 不要单看 Nginx,要看整条调用链
线上最常见的误区是:
既然报错发生在 Nginx,就只改 Nginx。
实际上一条请求可能同时经过:
- 浏览器或 SDK 自己的超时
- CDN / WAF / 云负载均衡超时
- Nginx 超时
- 应用服务器超时
- 应用里的 HTTP client 超时
- 数据库、缓存、消息队列、第三方 API 超时
这些超时如果配置得前后矛盾,就会出现很难排查的问题。
9.1 一个常见反模式
- 前端 30 秒超时
- Nginx
proxy_read_timeout 300s - 应用内部调用数据库超时 600s
结果是:
- 用户 30 秒就走了
- Nginx 还在等
- 后端还在查数据库
- 整条链路白白占资源
这类配置非常低效。
更合理的思路通常是:
- 最外层超时要和用户体验预期一致
- 越往内层,超时通常应略短于外层,而不是更长很多
- 长任务不要伪装成同步短请求
9.2 一个可操作的经验原则
虽然没有绝对公式,但很多系统会遵循类似策略:
- 调用方超时略短于网关可等待时间
- 网关超时略短于上游应用可容忍时间
- 上游应用访问下游依赖时,超时再更短一点
这样做的目标是让失败尽早在更靠里的地方被感知和释放,而不是把压力一层层往外拖。
10. 为什么 timeout 不能无脑调大
把 timeout 调大,短期看似能“减少报错”,但代价经常被低估。
10.1 连接会被占更久
每一个长时间挂着的请求,都可能占住:
- socket
- 文件描述符
- worker 处理资源
- upstream 连接池位置
- 应用线程或协程
如果慢请求一多,系统吞吐量会明显下降。
10.2 故障传播更慢,但更深
如果后端已经雪崩,短 timeout 会让问题快速暴露;长 timeout 则可能让更多请求堆进去,直到把更多组件一起拖垮。
这和“快速失败”是同一个工程原则。
10.3 用户体验不一定更好
用户等待 10 秒和等待 120 秒,很多时候感受上不是线性变差,而是前者还能接受,后者已经放弃。
所以 timeout 的本质不是“越大越稳”,而是:
用合理的等待上限,保护系统和用户体验。
11. 一套更实用的排障顺序
线上遇到 timeout,不建议上来就改配置。更稳妥的顺序通常是:
- 先确认是客户端到 Nginx 慢,还是 Nginx 到上游慢
- 看状态码是
408、499、502还是504 - 结合 access log 和 error log 判断卡在哪个阶段
- 确认是不是 DNS、建连、发送、读取这四类中的哪一类
- 再决定是调 timeout,还是修后端性能、网络、连接池、SQL、线程池
11.1 你至少要回答这几个问题
- 请求有没有到达上游应用
- 上游是根本没收到,还是收到了但处理很慢
- 是首字节迟迟不来,还是中途流断了
- 客户端有没有提前取消
- 整条链路上是否还有别的网关比 Nginx 更早超时
如果这些问题没答清楚,直接改 timeout,大概率只是碰运气。
12. 给一份相对稳妥的理解框架
如果你只想记住最核心的东西,可以记这一版:
client_*_timeout管客户端把请求交给 Nginxproxy_*_timeout管 Nginx 把请求交给上游并等待响应send_timeout管 Nginx 把响应发回客户端keepalive_timeout管请求结束后连接还能闲置多久- 大多数 timeout 管的是“空闲间隔”,不是“整个请求总时长”
504往往不是把 timeout 调大就能真正解决,根因通常在后端
把这六点真正理解透,Nginx 里大部分 timeout 配置就已经不会再混乱了。
13. 结语
Nginx 的 timeout 看起来只是一些普通配置项,但它背后其实是在回答一个很工程化的问题:
一个系统愿意为哪一类等待付出多大代价。
等待客户端、等待上游、等待 DNS、等待下一次复用连接,这些等待都不是免费的。
所以 timeout 的设计,本质上是在做平衡:
- 平衡用户体验和系统保护
- 平衡吞吐和容错
- 平衡“不要误杀正常慢请求”和“不要放任异常请求长期占资源”
如果你以后再看到一条超时配置,不要先问“该改多大”,而是先问:
- 这是哪一段链路的等待
- 它限制的是总时长,还是 I/O 空闲间隔
- 如果这个阶段长期变慢,真正的根因会在哪里
把这三个问题想清楚,你配 timeout 的准确率会高很多。