前言
proxy buffer是归属在proxy分支下的一组可配置项,用于配置代理的缓冲区,网上也有相关的文章对这组配置进行介绍,但尚未对配置的原因进行讲解,本篇文章将结合实际场景来介绍一下代理缓冲区相关的配置。
问题背景
前不久刚好在测试环境的后台服务器中看到了这样一个报错,从报错信息来看似乎是服务器的IO有问题,具体的表现是接口的数据未能够正常的返回,上网查了相关的资料,基本都是说nginx的配置有问题。
Suppressed: org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:351)
at org.apache.catalina.connector.OutputBuffer.flushByteBuffer(OutputBuffer.java:776)
at org.apache.catalina.connector.OutputBuffer.append(OutputBuffer.java:681)
at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:386)
at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:364)
at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:96)
at com.fasterxml.jackson.core.json.UTF8JsonGenerator._flushBuffer(UTF8JsonGenerator.java:2137)
at com.fasterxml.jackson.core.json.UTF8JsonGenerator.close(UTF8JsonGenerator.java:1180)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal
网上提到的需要修改的nginx配置如下:
proxy_buffer_size 16k;
proxy_buffers 8 16k;
proxy_busy_buffers_size 32k;
proxy_temp_file_write_size 32k;
配置介绍
这几个配置是什么意思呢?我们继续了解一下
1、缓冲区开关:proxy_buffering(这个配置因为默认是打开的,所以上面就没写)
语法:proxy_buffering on|off
默认值:proxy_buffering on
上下文:http,server,location
作用:该指令开启从后端被代理服务器的响应body缓冲。 如果proxy_buffering
开启,nginx假定被代理的后端服务器会以最快速度响应,并把内容保存在由指令 proxy_buffer_size
和 proxy_buffers
指定的缓冲区里边。如果响应body无法放在内存里边,那么部分内容会被写到磁盘上。
如果proxy_buffering
被关闭了,那么响应body会按照获取body的多少立刻同步传送到客户端。nginx不尝试计算被代理服务器整个响应body的大小,nginx能从服务器接受的最大数据,是由指令 proxy_buffer_size
指定的。
但是无论proxy_buffering
是否开启,proxy_buffer_size
都是生效的
2、代理缓冲区大小:proxy_buffers
Syntax: proxy_buffers number size;
Default: proxy_buffers 8 4k|8k;
Context: http, server, location
作用:设置存储被代理服务器响应的body所占用的buffer个数和每个buffer大小,具体的意思是说,开辟256个长度为8k大小的read_buf用来存储body,当然不是连接建立初始化时就开辟256个,而是当当前buf不够存响应body时才会新申请一个,最多申请256个buf。
3、代理缓冲区第一部分响应内容大小:proxy_buffer_size
Syntax: proxy_buffer_size size;
Default: proxy_buffer_size 4k|8k;
Context: http, server, location
作用:该指令设置缓冲区大小,从代理后端服务器取得的第一部分的响应内容会放到这里。小的响应header通常位于这部分响应内容里边。默认来说,该缓冲区大小等于指令 proxy_buffers所设置的;但是,你可以把它设置得更小。如果响应头超过了这个长度,Nginx会报upstream sent too big header错误,然后client收到的是502。
4、代理繁忙缓冲区大小:proxy_busy_buffer_size
Syntax: proxy_busy_buffers_size size;
Default: proxy_busy_buffers_size 8k|16k;
Context: http, server, location
作用:proxy_busy_buffers_size
不是独立的空间,他是proxy_buffers
和proxy_buffer_size
的一部分。
nginx会在没有完全读完后端响应就开始向客户端传送数据,所以它会划出一部分busy状态的buffer来专门向客户端传送数据(建议为proxy_buffers中单个缓冲区的2倍),然后它继续从后端取数据。
proxy_busy_buffer_size
参数用来设置处于busy状态的buffer有多大。
1)如果完整数据大小小于busy_buffer大小,当数据传输完成后,马上传给客户端;
2)如果完整数据大小不小于busy_buffer大小,则装满busy_buffer后,马上传给客户端;
5、每次写入磁盘临时文件的大小:proxy_temp_file_wirte_size
作用:该参数用于设置每次写入磁盘临时文件的大小。通常该参数值设置为proxy_buffer_size
和proxy_buffers
中单个buffer之和,也就是单个内存页的2倍。
小结
从配置的内容来看,上述配置都是属于代理模块的,配置的内容和缓冲区相关,在尝试加配置之前,我们先来聊一下缓冲区在nginx交互中所起到的作用。我们知道不同的设备的IO效率不同,cpu要显著高于内存,而内存的IO效率又要高于硬盘,为了适配不同IO效率的设备计算机内通过缓冲区来进行兼容。nginx的缓冲区出现的原因其实也类似,为了适配不同设备之间的网络通信速率,一般来说被代理的后台服务器和nginx所在的服务器会是在相同的局域网内(甚至是同一台服务器上面),所以二者间的通信速度是十分高的。而对于客户端来说,用户和nignx的连接网速可能并不快,所以如果我们把响应内容凑整之后再发给客户端,可以在一定长度上降低数据包传输的次数,节省用户带宽。
基于这个原则,若不考虑客户端的网速的话,其实是缓冲区的配置其实是可以不用设置的,只需要把被代理服务器的响应一股脑全部返回出去给客户端就行。且如果我们的响应内容不会很大的话,其实这个缓冲区的配置其实并没有让我们的系统变得更加高效多少。当然了,解释了这么多只是想让各位读者清楚缓冲区的本质作用,作为可配置项大部分时候我们还是会对这个参数来进行优化的。
问题解决
配置上上述的参数后,发现nginx和被代理服务器果然没有了相关的报错,这时我不禁想缓冲区的本质只是把响应内容缓冲下来而已,即使默认的内存缓冲区很小,但不还是有磁盘作为底线吗?默认的磁盘临时缓冲区域可是有1M的,不应该会出现IO阻塞的问题。
接着我又查看了nignx的error.log日志,发现缓冲数据在存放在磁盘上面的时候由于权限不足而失败了,这才是导致出现报错的直接原因。
2024/02/18 10:22:11 [crit] 23314#0: *29092 open() "/opt/nginx/proxy_temp/1/11/0000000111" failed (13: Permission denied) while reading upstream, client: 10.xxx, server: xxxx.com, request: "GET /xxx HTTP/1.1", upstream: "http://xxxx:8000/xxxx", host: "xxxx.com", referrer: "https://xxxx.com/"
通过授权的方式,最后解决了上述问题,同时基于可能出现的问题也同步对代理缓冲区相关的配置进行了优化。
网友评论