nginx 的连接、发送、读取三个超时到底各管什么?一个一点一点滴出来的响应会不会超时?超时遇上重试,client 要等多久?这篇用原始 socket 扮演各种坏上游把它们量出来。
超时 | client 看到 | client 等了 | error.log 里的原因 -------+-----------+---------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------- (1) 连接 | 504 | 1.01 s | 83299#0: *2 upstream timed out (60: Operation timed out) while connecting to upstream, client: 127.0.0.1, server: , request: "GET / HTTP/1.1", upstrea (2) 发送 | 504 | 1.04 s(含 client 把 30 MB 交给 nginx 的时间) | 83305#0: *2 upstream timed out (60: Operation timed out) while sending request to upstream, client: 127.0.0.1, server: , request: "POST / HTTP/1.1", u (3) 读取 | 504 | 1.00 s | 83314#0: *2 upstream timed out (60: Operation timed out) while reading response header from upstream, client: 127.0.0.1, server: , request: "GET / HTT
连接、发送、读取分别在不同阶段触发,都回 504,区别在 error.log 里。
上游行为 | client 看到的状态码 | client 收到的响应体 | client 等了 | error.log -----------------------+----------------+---------------+-----------+--------------------------------------------------------------------------------------------------------------------------------------------- (a) 先沉默 1.5 s 再回 | 504 | 167 字节(声明 8) | 1.01 s | 83374#0: *2 upstream timed out (60: Operation timed out) while reading response header from upstream, client: 127.0.0.1, server: , request: (b) 头先到,之后每 0.4 s 一个字节 | 200 | 8 字节(声明 8) | 3.25 s | (c) 头和 4 字节先到,停 1.5 s | IncompleteRead | 0 字节(声明 8) | 1.00 s | 83547#0: *2 upstream timed out (60: Operation timed out) while reading upstream, client: 127.0.0.1, server: , request: "GET / HTTP/1.1", ups (b) 整个响应花了 3.2 s,但每次读之间最多隔 0.4 s,从来没触发 1 s 的读取超时;(c) 响应头已经发给 client(状态码 200)之后上游才卡住,nginx 无法再改状态码,只能把连接断掉,client 收到的是残缺的响应体
是两次读之间的间隔,不是总时长;响应头发出后上游卡住,nginx 只能断开连接。
配置 | GET:状态码 · 等了 | POST:状态码 · 等了 -----------------------------+--------------+-------------- 默认 | 504 · 2.01 s | 504 · 1.00 s next_upstream_tries 1 | 504 · 1.00 s | 504 · 1.00 s next_upstream_timeout 1500ms | 504 · 2.01 s | 504 · 1.01 s next_upstream_timeout 800ms | 504 · 1.00 s | 504 · 1.00 s 默认配置下 GET 先在第一个上游等满 1 s 超时,再去第二个上游又等满 1 s,client 一共等了约两倍的读取超时;POST 请求已经发给上游,出错后默认不再重试(非幂等),所以只等一个读取超时;next_upstream_tries 1 让 GET 也只试一次。proxy_next_upstream_timeout 限制的是“还允许换上游重试的时间窗”,不是总时长:设 1500ms 时第二次尝试在 1.0 s 开始(窗口还没过),它仍然跑满自己的 1 s 读取超时,总共还是约 2 s;设 800ms 时 1.0 s 已经超出窗口,不再换上游,总共约 1 s
GET 会在下一个上游再等满一个超时;next_upstream_timeout 限制的是还能重试的窗口。