1.问题情况

最近发现nginx日志出现大量的这种错误:an upstream response is buffered to a temporary file

2023/01/17 15:14:14 [warn] 18239#18239: *1258333 an upstream response is buffered to a temporary file /usr/local/openresty/nginx/proxy_temp/4/83/0000008834 while reading upstream, client: 103.63.154.88, server: localhost, request: "GET /course?pid=%5B%22CD-01%22%2C%22MG-061S%22 HTTP/1.1", upstream: "http://xxx.xxx.xx.xxx:8804/course?pid=%5B%22CD-01%22%2C%22MG-061S%22", host: "api.xxxxxxx.com:1443"
2023/01/17 15:24:21 [warn] 18239#18239: *1258594 an upstream response is buffered to a temporary file /usr/local/openresty/nginx/proxy_temp/5/83/0000008835 while reading upstream, client: 111.201.131.113, server: localhost, request: "GET /courseid_ls=%5B%22100006%22%5D HTTP/1.1", upstream: "http://xxx.xxx.xx.xxx:8804/course/v1/route?id_ls=%5B%22100006%22%5D&pid=MG03&with_route_point=1", host: "api.xxxxxxxxx.com:1443"

研究了一下,了解到是nginx buffer默认太小导致把buffer写入文件导致的提示。

然后顺便把buffer的配置给梳理一下

2.buffer工作原理

首先第一个概念是所有的这些proxy buffer参数是作用到每一个请求的。每一个请求会安按照参数的配置获得自己的buffer。proxy buffer不是global而是per request的。proxy_buffering 是为了开启response buffering of the proxied server,开启后proxy_buffers和proxy_busy_buffers_size参数才会起作用。
无论proxy_buffering是否开启,proxy_buffer_size(main buffer)都是工作的,proxy_buffer_size所设置的buffer_size的作用是用来存储upstream端response的header。

在proxy_buffering 开启的情况下,Nginx将会尽可能的读取所有的upstream端传输的数据到buffer,直到proxy_buffers设置的所有buffer们被写满或者数据被读取完(EOF)。此时nginx开始向客户端传输数据,会同时传输这一整串buffer们。同时如果response的内容很大的话,Nginx会接收并把他们写入到temp_file里去。大小由proxy_max_temp_file_size控制。如果busy的buffer传输完了会从temp_file里面接着读数据,直到传输完毕。

一旦proxy_buffers设置的buffer被写入,直到buffer里面的数据被完整的传输完(传输到客户端),这个buffer将会一直处在busy状态,我们不能对这个buffer进行任何别的操作。所有处在busy状态的buffer size加起来不能超过proxy_busy_buffers_size,所以proxy_busy_buffers_size是用来控制同时传输到客户端的buffer数量的。

3.buffer配置项

3.1. proxy_buffering

 

语法:proxy_buffering on|off
默认值:proxy_buffering on
上下文:http,server,location

作用:该指令开启从后端被代理服务器的响应body缓冲。
如果proxy_buffering开启,nginx假定被代理的后端服务器会以最快速度响应,并把内容保存在由指令 proxy_buffer_size 和 proxy_buffers 指定的缓冲区里边.
如果响应body无法放在内存里边,那么部分内容会被写到磁盘上。(大于proxy_buffers)
如果proxy_buffering被关闭了,那么响应body会按照获取body的多少立刻同步传送到客户端。nginx不尝试计算被代理服务器整个响应body的大小,nginx能从服务器接受的最大数据,是由指令 proxy_buffer_size指定的。
对于基于长轮询(long-polling)的Comet 应用来说,关闭 proxy_buffering 是重要的,不然异步响应将被缓存导致Comet无法工作。
但是无论proxy_buffering是否开启,proxy_buffer_size都是生效的

3.2. proxy_buffers

 

语法:proxy_buffers  数量  size
默认值:proxy_buffers 256 8k
上下文:http,server,location

作用:设置存储被代理服务器响应的body所占用的buffer个数和每个buffer大小。
具体的意思是说,开辟256个长度为8k大小的read_buf用来存储body,当然不是连接建立初始化时就开辟256个,而是当当前buf不够存响应body时才会新申请一个,最多申请256个buf。

3.3. proxy_buffer_size

 

语法:proxy_buffer_size size
默认值:proxy_buffer_size 4k/8k
上下文:http,server,location

作用:Nginx使用该大小申请read_buf,即大小指定了 upstream header 最大长度,如果响应头超过了这个长度,Nginx会报upstream sent too big header错误,然后client收到的是502。

3.4. proxy_busy_buffer_size

 

语法:proxy_busy_buffer_size  size
上下文: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后,马上传给客户端;

3.5. proxy_temp_path

 

语法:proxy_temp_path  path [level1 level2 level3]
默认值:proxy_temp_path proxy_temp
上下文:http,server,location

作用:定义proxy的临时文件存在目录以及目录的层级。

3.6. proxy_max_temp_file_size

 

语法:proxy_max_temp_file_size size;
默认值:proxy_max_temp_file_size 1024m;
上下文:http, server, location

作用:设置临时文件的总大小

3.7. proxy_temp_file_wirte_size

作用:设置同时写入临时文件的数据量的总大小。通常设置为8k或者16k。

根据上面的说明.我在nginx.conf的header里添加了

语法:proxy_temp_file_write_sizesize;
默认值:proxy_temp_file_write_size 8k|16k;
上下文:http, server, location

4.实例

 

worker_processes  1;
error_log  /usr/local/openresty/nginx/logs/error.log warn;
pid        /usr/local/openresty/nginx/logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    # proxy setting
    proxy_buffering on; # Enables or disables buffering of responses from the proxied server.
    proxy_buffer_size 32k; # Sets the size of the buffer used for reading the first part of the response received from the proxied server
    proxy_buffers 32 32k; # Sets the number and size of the buffers used for reading a response from the proxied server
    proxy_busy_buffers_size 64k; #(proxy_buffers*2) When buffering of responses from the proxied server is enabled, limits the total size of buffers that can be busy sending a response to the client while the response is not yet fully read
    proxy_temp_file_write_size 128k; # Limits the size of data written to a temporary file at a time

    server {
        listen 80;
        server_name  localhost;

        location / {
            root   /usr/local/openresty/nginx/html;
            index  index.html index.htm;
        }
    }
}