proxy_send_timeout 在 Nginx 中到底做了什么?

hna*_*asr 19 nginx

在 Nginx 文档中,有关于三种不同网络超时的指令,可以为“后端”服务器配置这些超时,如下所示:

proxy_connect_timeout定义与代理服务器建立连接的超时。需要注意的是,这个超时时间通常不能超过75秒。

这很容易理解——Nginx 即将连接到上游“后端”服务器,如果它无法在 X 时间内连接,它将放弃并返回错误。服务器无法访问、连接过多等。

proxy_read_timeout定义从代理服务器读取响应的超时。仅在两个连续的读取操作之间设置超时,而不是为整个响应的传输设置超时。如果代理服务器在此时间内未传输任何内容,则连接将关闭。

这也是有道理的——Nginx 已经与“后端”服务器建立了 TCP 连接,现在即将实际发送请求,但是服务器需要很长时间来处理,如果需要超过 X 时间,则关闭连接并返回给用户。

事实上,我很惊讶 Nginx 关闭了连接,我认为它会保留连接,但会向用户返回一个错误。每次发生超时时重新建立这些“后端”TCP 连接听起来成本很高。

proxy_send_timeout设置将请求传输到代理服务器的超时。仅在两个连续的写入操作之间设置超时,而不是为整个请求的传输设置超时。如果代理服务器在此时间内未收到任何内容,则连接将关闭。

这个我不太明白。我确实有一个理论,但我希望有人证实它。我能想到的这个超时的唯一值是请求负载是否很大(例如,带有 JSON 的大型 POST 请求,或用户想要保存的文档)。将请求传输到“后端”需要将请求分解为更小的 MTU TCP 段,并将它们作为原始请求的“块”发送。因此从技术上讲,直到我们成功地将所有块传输到服务器之前,我们实际上并没有发送请求。Nginx 是否测量每个请求块之间的时间?这就是文档中“写”的意思吗?一旦请求实际发送,Nginx 将开始测量proxy_read_timeout?

amn*_*amn 7

TCP/IP 是所谓的“流式”数据传输协议。它旨在让通过 TCP/IP 连接读取数据的一方不必关心“段”甚至数据包的大小。这意味着,在实践中,对等点调用一些传统的“读取”操作来获取远程对等点(例如read使用Linux)发送的数据,不一定会立即读取与远程端提供的数据一样多的数据。到单个“写”操作。TCP/IP 协议实现总是会根据一次传递给“写”操作的内容生成适当大小的 IP 数据包,而另一端的实现将从这些数据包中组装回数据;但它不一定会将它们交给具有相同数据边界的某些“读取”客户端应用程序!

示例:A 有 50Kb 的数据要为每个外部系统事件发送,如此之多以至于他们无法同时将其全部放入 RAM,因此他们以 16Kb 的块发送数据,这是其发送缓冲区的大小。因此,他们首先发送 16Kb,然后再发送 16Kb,然后再发送 16Kb,最后发送 2Kb。TCP/IP 实现可能会发送这些 50Kb,缓冲在内部 128Kb 缓冲区(例如内核缓冲区)中,然后才通过网络发送,这也有其自身的条件。其中一些数据以发送应用程序甚至不知道的方式分段,由于网络条件而首先到达另一端,并由那里的 TCP/IP 实现进行组装并放入内核缓冲区中再次。内核唤醒想要读取数据的进程——读取全部 30Kb。接收者必须决定他们是否期望更多以及如何理解期望的程度—— “消息”或数据的格式不是 TCP/IP 关心的事情。

这意味着 Nginx 无法知道read在基于 Linux 的系统上每次调用时它会立即读取多少客户端请求。

不过,文档proxy_send_timeout稍微暗示了它的用途(强调我的):

设置将请求传输到代理服务器的超时。仅在两个连续的写入操作之间设置超时,而不是为整个请求的传输设置超时。如果代理服务器在此时间内未收到任何内容,则连接将关闭。

事实是,由于 Nginx代理一个请求——这意味着该请求不是由它发起的——它等待“下游”客户端(将请求发送到 Nginx 的连接的远程端,后者的角色是“ proxy”现在期望转发上游),以在通过上游连接转发(写入)请求之前传输请求的数据。

我的理解是,如果[在超时期间]没有从下游接收到任何内容,那么代理服务器也不会接收到任何内容——然后连接就会关闭。

换句话说,如果下游在 指定的时间内没有发送任何内容proxy_send_timeout,Nginx 将关闭与上游的连接。

例如,考虑一个向 Nginx 发送请求的 Web 浏览器。第一部分由 Nginx 在时间 A 读取。假设它将请求代理到某个上游,它会打开到所述上游的连接,并通过上游连接套接字传输(写入)从浏览器接收到的内容。然后,它只是等待从浏览器读取更多的请求数据——如果在相对于时间 A 的某个超时 X 后下一个数据还没有到达,它将关闭与上游的连接。

请注意,这并不一定意味着它将关闭与 Web 浏览器的连接——它肯定会为请求返回一些 HTTP 错误状态代码,但 Web 浏览器连接生命周期由一组不同的条件控制proxy_send_timeout——后者仅涉及 Nginx 与上游的连接。