代理请求就是将请求先发送到指定的代理服务器,获取响应,然后将其发送回客户端。当然请求可能被代理到
http
服务器(proxy_pass
)也可能不是http
服务器。(nginx
支持的协议包括FastCGI
,uwsgi
,SCGI
, 和memcached
.它们对应的指令分别是fastcgi_pass
,uwsgi_pass
,scgi_pass
,memcached_pass
; 这几个指令都不属于今天要说的proxy
模块。在此就不作说明了。而且我也没用过。。。)
首先要发送代理请求给后端代理服务,这就得用到 proxy_pass
指令了,因为这个指令我在之前的一篇文章中已经对其使用中的注意点作出说明,所以这里就不再阐述了。
proxy_http_version 1.0|1.1proxy_http_version 1.0 | 1.1;
设置代理的HTTP协议版本。默认情况下,使用版本1.0
。可以将其改为1.1来往后端方向发往1.1的请求,比如在使用http keepalive功能的时候就必须改为1.1,因为1.0不支持
proxy_method method
指定在转发到代理服务器的请求中使用的HTTP
方法,而不是来自客户端请求的方法。参数值可以包含变量
http_proxy在为上游生成请求的时候提供了许多指令,这些指令可以修改转发给上游HTTP请求的内容
构造发往上游HTTP请求的内容会影响上游服务器怎么处理这个请求,包括对缓存,对host头部,对keepalive等等的诸多特性。所以要熟悉利用nginx更改转发个上游的内容。
默认情况下,nginx 重新定义代理请求
Host
和Connection
中的两个头字段,并删除了值为空字符串的头字段。其中请求头Host
被设置为了变量$proxy_host
,Connection
被设定为close
。
所以为了改变这些设置,我们可以使用如下指令。
1.proxy_set_header
Syntax: proxy_set_header field value; 修改或设置请求头的值
Default: proxy_set_header Host $proxy_host;
proxy_set_header Connection close;(要启用对后端使用keepalive要设置为Connection “”,即更改默认的close的值,close是不会启用keepalive)
Context: http, server, location
请求头的值value
可以是变量,文本或者是它们的组合,如果value
为空字符串那么这个字段将不会被转发到代理服务器。
如果nginx
缓存被启用了的话,从原始请求发过来的如下请求头 If-Modified-Since
, If-Unmodified-Since
, If-None-Match
, If-Match
, Range
, If-Range
, 是不会被转发到代理服务器的
2.proxy_pass_request_headers
指定是否将原始的请求头转发给后端服务。如果要忽略掉所有的原始请求头,则可以关闭此值。默认值为on
。即不忽略。
3.proxy_ignore_headers
告知nginx
后端服务的响应中的哪些响应头不要去被处理,如下几个响应头可以被忽略:X-Accel-Redirect
、X-Accel-Expires
、X-Accel-Limit-Rate
、X-Accel-Buffering
、X-Accel-Charset
、Expires
、Cache-Control
、Set-Cookie
、Vary
。
你如果指定这些之外的响应头的是不被允许的。因为只有这些响应头nginx
才回去解析并应用它们。
如果后端服务设置了这些响应头,但是你没有忽略它们,则它们可能对nginx有着如下影响X-Accel-Expires
、Expires
、Cache-Control
、Set-Cookie
、Vary
将会影响nginx
的缓存机制。X-Accel-Redirect
执行一个内部跳转到指定的uri
X-Accel-Limit-Rate
将会影响响应到客户端的传输速度X-Accel-Buffering
启用或者警用响应的缓冲区X-Accel-Charset
影响 响应的字符集
4.proxy_hide_header
此指令在 nginx
将请求的响应结果给客户端的时候,将后端响应的一些请求头过滤掉
默认nginx
不会将响应中的Date
、Server
、X-Pad
、X-Accel-...
等响应头发送给客户端。而proxy_hide_header
指令则是继续设置不需要发送的其他的响应头;当然,对于你想把上面被忽略掉的响应头传递给客户端,你可以使用proxy_pass_header
指令指定。
5.proxy_pass_headerproxy_hide_header
指令默认不会把上面列举的那几个header
传递给客户端,那么proxy_pass_header
则允许其中某个响应头传递给客户端。
6.proxy_headers_hash_bucket_size 和 proxy_headers_hash_max_size(这两个不是太清楚。。。所以就不说了,希望知道的同学告知一下)
# 如下配置只是学习之用
upstream backend {
server 10.5.20.3:3100;
server 10.5.20.3:3101;
server 10.5.20.3:3102;
server 10.5.20.3:3103;
}
server {
listen 8080;
location / {
# 忽略掉所有原始请求头
proxy_pass_request_headers off;
# 修改host头
proxy_set_header Host $host;
# 此处显示server头给客户端 要不客户端显示的是代理服务器的server
# Server → openresty/1.9.7.3
proxy_pass_header Server;
proxy_pass http://backend;
}
}
很多用户担心添加服务器会对代理性能造成影响。大部分情况下,Nginx
的缓冲(buffer)和缓存(cache
)机制能够很好的规避此类性能问题。
代理过程中,有两个连接的速度会影响客户端体验:
(1).从客户端到Nginx的连接
(2).从Nginx
到后端的连接
Nginx
可以优化连接,不同的优化方案有不同的结果。
没有缓冲的情况下,数据直接从后端服务器发送给客户端。如果客户端的连接速度快,则可以关闭缓冲以提高数据发送速度。缓冲的作用是在Nginx
上临时存储来自后端服务器的处理结果,从而可以提早关闭Nginx
到后端的连接,这比较适合客户端连接较慢的情况。
Nginx
默认启用缓冲,因为客户端的连接速度一般来说是差别很大的。缓冲的具体配置可以通过如下条目修改,这些条目可以放在http
,server
或location
内容块下。需要注意的是,涉及缓冲大小的条目是针对请求配置的,如果设置的比较高,则请求数很多的时候容易造成性能问题:
1.proxy_buffering
是否对后端服务的响应启用缓冲,默认为on
。
proxy_buffering主要是实现被代理服务器的数据和客户端的请求异步。为了方便理解,我们定义三个角色,A为客户端,B为代理服务器,C为被代理服务器。
当proxy_buffering开启,A发起请求到B,B再到C,C反馈的数据先到B的buffer上,然后B会根据proxy_busy_buffer_size来决定什么时候开始把数据传输给A。在此过程中,如果所有的buffer被写满,数据将会写入到temp_file中。相反,如果proxy_buffering关闭,C反馈的数据实时地通过B传输给A。
2.proxy_buffers
有两个参数,第一个控制缓冲区请求数量,第二个控制缓冲区大小。默认值为8个、一页(一般是4k或8k)。这个值越大,缓冲的内容越多。
这个参数设置存储被代理服务器上的数据所占用的buffer的个数和每个buffer的大小。所有buffer的大小为这两个数字的乘积。
3.proxy_buffer_size
后端回复结果的首段(包含header的部分)是单独缓冲的,本条目定义这部分的缓冲区大小。这个值默认与proxy_buffer的值相同,我们可以把它设置的小一些,因为header内容一般比较少。
该参数用来设置一个特殊的buffer大小的。从被代理服务器(C)上获取到的第一部分响应数据内容到代理服务器(B)上,通常是header,就存到了这个buffer中。 如果该参数设置太小,会出现502错误码,这是因为这部分buffer不够存储header信息。建议设置为8k。
4.proxy_busy_buffers_size
设置被标记为“client-ready”(客户端就绪)的缓冲区大小。客户端一次只能从一个缓冲读取数据,而缓冲是按照队列次序被分批发送给客户端的。本条目设置的值就是这个队列的大小。
在所有的buffer里,我们需要规定一部分buffer把自己存的数据传给A,这部分buffer就叫做busy_buffer。proxy_busy_buffer_size参数用来设置处于busy状态的buffer有多大。
对于B上buffer里的数据何时传输给A,个人的理解是这样的:
1)如果完整数据大小小于busy_buffer大小,当数据传输完成后,马上传给A;
2)如果完整数据大小不少于busy_buffer大小,则装满busy_buffer后,马上传给A;
5.proxy_temp_path
定义Nginx
存储临时文件的路径。
语法:proxy_temp_path path [level1 level2 level3]
定义proxy的临时文件存在目录以及目录的层级。path下面会建立多级子目录lev1,lev2,lev3,之所以这样做的原因是一个目录下面不能存放太多的文件,如果存放太多的文件会导致这个目录存取速度非常的慢。所以通过多级子目录来讲解决这种场景。
例:proxy_temp_path /usr/local/nginx/proxy_temp 1 2;
其中/usr/local/nginx/proxy_temp为临时文件所在目录,1表示层级1的目录名为1个数字(0-9),2表示层级2目录名为2个数字(00-99)
6.proxy_max_temp_file_size
设置临时文件的总大小,例如 proxy_max_temp_file_size 100M;
7.proxy_temp_file_write_size
限制一次性写入临时文件的数据大小,通常设置为8k或者16k。
上面是被代理的服务响应的body处理方式(接收上游的HTTP包体)
下面是客户端请求的body的处理方式
8.proxy_request_buffering(接收客户端请求的包体:收完再转发还是边收边转发)
控制本内容块下(包括子内容块)是否对客户端的请求体启用缓冲,默认为on
。启用的话,nginx
会从客户端读取完整个请求包体后再将请求发送到后端服务器去。下面启用on和off分别对应三种场景。
打开on以后非常依赖nginx处理能力,nginx本身的处理能力就很强。所以采用on的方式适用于高吞吐量场景。
打开off以后这样上游可以更快的接收到用户发来的请求,而不需要等待nginx先接受完请求,上游可以及时的响应。同时Nginx需要将用户请求的body写入到磁盘当中,如果超出其内存大小的话,然后向上游发送的时候需要再次读取磁盘,使用off可以降低磁盘消耗。
9.proxy_pass_request_body
指定是否将原始的请求体转发给后端服务。如果要忽略掉所有的原始请求体,则可以关闭此值。默认值为on
。即不忽略。
10.proxy_set_body
重新设置这个请求体然后在发送到后端服务器。proxy_set_body value;
这个value
值可以是纯文本,变量或者是它们的组合形式
如上所述,Nginx
提供了不少关于缓冲的配置项。大部分配置项我们都不必太在意,可能就是proxy_buffers和
proxy_buffer_size
值得调整一下。
下面这个示范增加了每个上游请求可用的缓冲,同时缩减了header
部分缓冲的大小:
# server context
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 6k;
proxy_temp_path /tmp/nginx_proxy_tmp 1 2;
proxy_max_temp_file_size 20M;
proxy_temp_file_write_size 64k;
location / {
proxy_pass http://example.com;
}
如果你的客户端连接都很快,也可以像下面这样完全关闭缓冲。实际上Nginx
还是会在上游比客户端快的时候使用缓冲,只是缓冲的内容会直接刷给客户端而不是放到缓冲池里等待。如果客户端的速度慢,则这样会导致上游连接一直保持。缓冲功能禁用时,只有proxy_buffer_size
配置项可用:
# server context
proxy_buffering off;
proxy_buffer_size 4k;
location / {
proxy_pass http://example.com;
}
最后举一个生产环境常用配置:
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;