极客专栏《Nginx核心知识100讲》93小节,笔记
注意:这个是看专栏视频,敲的哈。这个专栏让我收货蛮大的。
93 | 接收上游的响应
上游服务接收到请求就会生成响应。接下来看看nginx怎样处理上游发来的响应,包括http header 和http body。
接收头部
image.pngproxy_buffer_size:这个指令非常重要。如果你在开源nginx官网去看这个指令的描述,其实非常的简单,没有说出很重要的问题。就是proxy_buffer_size其实限定了我们接收自上游的http response中header的最大值。所以当上游的server发送了http响应,如果有set cookie这种特别长的header可能就会导致整个全部的response header超出了这个值。超出完之后这个请求就不能够被nginx正确的处理了。我们的error.log中会看到upstream sent too big header
就是这样的一个原因。
当把请求发送到上游服务,上游服务也返回了它的响应的时候。首先,先接收响应头部,再处理响应头部。这两个过程中。实际上接收是由我们的nginx的框架upstream来处理的。处理响应头部只是由各个反向代理模块,比如grpc、fastcgi、http proxy等等处理响应头部。会有一个最大的内存长度来限制,就是刚刚谈到的proxy_buffer_size,超出之后就会报错了。
我们处理响应头部有很多header是会产生一些不同作用的。放到下节细讲。
proxy_buffering:来控制我们是不是先接收完整的包体,接收完了才开始转发。或者说不接收完,而是每接收一部分就同步的向客户端发送我收到的那部分响应。这两种方式各有各的好处。通常情况下默认开启(on)。因为我们认为上游服务和我们nginx走的是内网,网速更快。如果我们边发边接收上游边往客户端发。因为客户端跟nginx之间的网速可能很慢。所以就会导致,对于比较大的body 的时候,nginx长时间与上游建立连接。而上游比如说tomcat、Django等它们的并发能力是很弱的。当然如果我们用了proxy_buffering off 它的优点是能让客户端及时接收到响应,特别是一些大包体的情况下。客户端不用再等待。
接收上游HTTP包体
image.png在我们接收上游发来的HTTP包体,即使我们开启了proxy_buffering on也并不一定向磁盘中写入包体,因为如果包体非常的小,在内存中就可以放入的话,就没有必要写到磁盘中,因为磁盘io总是比较慢的。所以这个时候就有了proxy_buffers指令。也就是包体大小没有超过这个设定值就不用写入磁盘。否则的话就要写入磁盘了。
image.png向磁盘写入body 的时候呢,还是我们刚刚介绍的指令 proxy_buffering ,默认开启,希望尽快释放上游服务器的连接,当然proxy_buffering 还有一个nginx特定的headr。这个header(X-Accel-Buffering头部)只有nginx才会认。当上游的tomcat 如果在response中加入X-Accel-Buffering头部,如果配置为yes,就会强制要求nginx先接收完上游的http body 再向client发送。也就是它会替换指定的内容。
当我们向磁盘中写入包体的时候还有三个指令,proxy_max_temp_file_size、proxy_temp_file_write_size、proxy_temp_path。
proxy_max_temp_file_size:限制写入磁盘中这个文件的最大值。如果上游服务中返回了非常大的文件超出了临时文件大小也会出错的。默认是1G。
proxy_temp_file_write_size:每一次向磁盘文件中写入的字节数。
proxy_temp_path:设定了存放临时文件的目录在哪里,以及目录level层级。
及时转发
nginx在开启buffering的时候还提供了一个非常灵活指令,proxy_busy_buffers_size。虽然被缓存所有的响应,我们希望更及时的向客户端发送部分响应。比如我们收到1G文件。当我们接收到前8k或前16k(proxy_busy_buffers_size 8k|16k)的时候,就先向客户端转发接收到的这一部分响应的话就可以使用proxy_busy_buffers_size 。
image.png接收上游网络速度相关指令
image.pngproxy_read_timeout:两次读取操作之间最多60秒的超时。两次读取是一个TCP层的一个概念。
proxy_limit_reate:限速,和客户端limit_rate 有些类似,但是它限制的是读取上游的响应,而不是发送给上游服务的网速。设置为0表示不限制读取上游响应的速度。
上游包体持久化
上游发回来的响应。也许是一个完整的文件,而这文件nginx应该把它存下来作为一个永久的服务。对客户端或者做其他用途。
image.pngproxy_store_access:配置指定目录权限。
proxy_store:把临时文件改名到root对应的目录下,默认不开启,如果是string
,可再次指定,使用变量的方式,指定这个文件存放的位置。
持久化例子
nginx配置
image.png上游服务配置
image.png访问html目录下的文件。
image.png然后看到temp目录下有这个文件了。
image.png留言问题
- 我们用 nginx 做缓存服务器,客户端用 head 请求,nginx 做转发缓存,我们以 http_code 是否为200来判断 文件缓存完成,实际是有问题的,nginx 会把 响应头信息,及时返回客户端。此时文件并没有缓存完。
怎么能做到当我收到 http_code 时候,文件已经缓存完成了呢?
作者回复
我补充下,你是说:nginx缓存上游的response,而client希望收到response时,且code是200,但还没有收完body,就想判断nginx缓存到完整的response body了吗?
我有个问题,为什么不等接收到完整的http response body再判断呢?因为body是有Content-Length头部标识的,客户端可以判断接收到完整的响应了,且code是200,此时就可以判断nginx缓存完成了。
2.nginx等待上游返回结果的时候,这个work进程中的线程是阻塞的状态吗?
作者回复
不是的,worker进程中没有线程(仅在读取磁盘时可以通过thread_pool配置线程)。worker进程仍然处于Running状态,而不是Sleep状态,除非没有其他可以处理的连接,非常空闲。
网友评论