Caleb0 2019-06-20
今天主要介绍nginx的模块——ngx_http_proxy_module和ngx_http_upstream_module,严格来说,nginx自带是没有针对负载均衡后端节点的健康检查的,但是可以通过默认自带的ngx_http_proxy_module 模块和ngx_http_upstream_module模块中的相关指令来完成当后端节点出现故障时,自动切换到健康节点来提供访问。
反向代理( reverse proxy) 方式是指用代理服务器来接受 Internet 上的连接请求, 然后将请求转发给内部网络中的上游服务器, 并将从上游服务器上得到的结果返回给 Internet 上请求连接的客户端, 此时代理服务器对外的表现就是一个 Web 服务器。 充当反向代理服务器也是 Nginx 的一种常见用法( 反向代理服务器必须能够处理大量并发请求)。
由于Nginx具有“强悍”的高并发高负载能力, 因此一般会作为前端的服务器直接向客户端提供静态文件服务。 但也有一些复杂、 多变的业务不适合放到 Nginx 服务器上, 这时会用Apache、 Tomcat 等服务器来处理。 于是, Nginx 通常会被配置为既是静态Web服务器也是反向代理服务器( 如下图所示), 不适合Nginx处理的请求就会直接转发到上游服务器中处理。
ngx_http_proxy_module模块允许传送请求到其它服务器,也就是做反向代理。下面提供一个基本的配置示例:
location / { root /usr/share/nginx/html; proxy_redirect default; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_connect_timeout 2; proxy_send_timeout 5; proxy_read_timeout 5; proxy_buffer_size 256k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k; proxy_pass http://127.0.0.1:80; }
ngx_http_proxy_module模块常用指令解释:
1)proxy_bind
Syntax: proxy_bind address [transparent] | off; Default: — Context: http, server, location This directive appeared in version 0.8.22.
在调用connect()前将上游socket绑定到一个本地地址,如果主机有多个网络接口或别名,但是你希望代理的连接通过指定的接口或地址,可以使用这个指令。
透明传输模式允许传出连接到代理服务器起源于一个非本地IP地址,例如,从一个真实的IP地址的客户端 ︰
proxy_bind $remote_addr transparent;
为了使此参数工作,就必须以超级用户的特权运行nginx的工作进程和配置内核路由表拦截来自代理服务器的网络流量。
2)proxy_buffer_size
Syntax: proxy_buffer_size size; Default:proxy_buffer_size 4k|8k; Context:http, server, location
设置缓冲区的大小为size,nginx从被代理的服务器读取响应时,使用该缓冲区保存响应的开始部分。这部分通常包含着一个小小的响应头。该缓冲区大小默认等于proxy_buffers指令设置的一块缓冲区的大小,但它也可以被设置得更小。
3)proxy_buffers
Syntax: proxy_buffers number size; Default:proxy_buffers 8 4k|8k; Context:http, server, location
设置用于读取应答(来自被代理服务器)的缓冲区数目和大小,为每个连接设置缓冲区的数量是number参数,每块缓冲区的大小是size参数。这些缓冲区用于保存从被代理的服务器读取的响应。每块缓冲区默认等于一个内存页的大小。这个值默认是4K还是8K,取决于平台。
4)proxy_buffering
Syntax: proxy_buffering on | off; Default:proxy_buffering on; Context:http, server, location
代理的时候,开启或关闭缓冲后端服务器的响应。
当开启缓冲时,nginx尽可能快地从被代理的服务器接收响应,再将它存入proxy_buffer_size和proxy_buffers指令设置的缓冲区中。
如果响应无法整个纳入内存,那么其中一部分将存入磁盘上的临时文件。proxy_max_temp_file_size和proxy_temp_file_write_size指令可以控制临时文件的写入。
当关闭缓冲时,收到响应后,nginx立即将其同步传给客户端。nginx不会尝试从被代理的服务器读取整个请求,而是将proxy_buffer_size指令设定的大小作为一次读取的最大长度。
响应头“X-Accel-Buffering”传递“yes”或“no”可以动态地开启或关闭代理的缓冲功能。 这个能力可以通过proxy_ignore_headers指令关闭。
5)proxy_busy_buffers_size
Syntax: proxy_busy_buffers_size size; Default:proxy_busy_buffers_size 8k|16k; Context:http, server, location
当开启缓冲响应的功能以后,在没有读到全部响应的情况下,写缓冲到达一定大小时,nginx一定会向客户端发送响应,直到缓冲小于此值。
这条指令用来设置此值。 同时,剩余的缓冲区可以用于接收响应,如果需要,一部分内容将缓冲到临时文件。该大小默认是proxy_buffer_size和proxy_buffers指令设置单块缓冲大小的两倍。
6)proxy_max_temp_file
Syntax: proxy_max_temp_file_size size; Default:proxy_max_temp_file_size 1024m; Context:http, server, location
打开响应缓冲以后,如果整个响应不能存放在proxy_buffer_size和proxy_buffers指令设置的缓冲区内,部分响应可以存放在临时文件中。 这条指令可以设置临时文件的最大容量。
而每次写入临时文件的数据量则由proxy_temp_file_write_size指令定义。
将此值设置为0将禁止响应写入临时文件。
7)proxy_temp_file_write_size
Syntax: proxy_temp_file_write_size size; Default:proxy_temp_file_write_size 8k|16k; Context:http, server, location
在开启缓冲后端服务器响应到临时文件的功能后,设置nginx每次写数据到临时文件的size(大小)限制。 size的默认值是proxy_buffer_size指令和proxy_buffers指令定义的每块缓冲区大小的两倍, 而临时文件最大容量由 proxy_max_temp_file_size指令设置。
8)proxy_temp_path
Syntax: proxy_temp_path path [level1 [level2 [level3]]]; Default:proxy_temp_path proxy_temp; Context:http, server, location
定义从后端服务器接收的临时文件的存放路径,可以为临时文件路径定义至多三层子目录的目录树。 比如,下面配置
proxy_temp_path /spool/nginx/proxy_temp 1 2;
那么临时文件的路径看起来会是这样:
/spool/nginx/proxy_temp/7/45/00000123457
9)proxy_connect_timeout
Syntax: proxy_connect_timeout time; Default:proxy_connect_timeout 60s; Context:http, server, location
设置与后端服务器建立连接的超时时间,应该注意这个超时一般不可能大于75秒。默认为60s,建议生产环境连接时间设置为1到2s。
10)proxy_http_version
Syntax: proxy_http_version 1.0 | 1.1; Default:proxy_http_version 1.0; Context:http, server, location This directive appeared in version 1.1.4.
设置代理使用的HTTP协议版本,默认使用的版本是1.0,而1.1版本则推荐在使用keepalive连接时一起使用。我接触的生产环境中都是设置http 1.1版本了。
11)proxy_ignore_client_abort
Syntax: proxy_ignore_client_abort on | off; Default:proxy_ignore_client_abort off; Context:http, server, location
决定当客户端在响应传输完成前就关闭连接时,nginx是否应关闭后端连接。
12)proxy_pass
Syntax: proxy_pass URL; Default:— Context:location, if in location, limit_except
设置后端服务器的协议和地址,还可以设置可选的URI以定义本地路径和后端服务器的映射关系。 这条指令可以设置的协议是“http”或者“https”,而地址既可以使用域名或者IP地址加端口(可选)的形式来定义:
proxy_pass http://localhost:8000/uri/;
对于URI可选,一般情况下使用是不需要指定的,除非你需要的访问方式就是这样的。
也可以使用UNIX域套接字路径来定义,该路径接在“unix”字符串后面,两端由冒号所包围,比如:
proxy_pass http://unix:/tmp/backend.socket:/uri/;
如果proxy_pass没有使用URI,传送到后端服务器的请求URI一般客户端发起的原始URI,如果nginx改变了请求URI,则传送的URI是nginx改变以后的完整规范化URI:
location /path/ { proxy_pass http://127.0.0.1; }
虚拟路径代理就是,比如说访问”http://127.0.0.1/path/uri”地址,当匹配到这个location之后,通过”proxy_pass http://127.0.0.1/”代理到后端时,一个新的URL就成了”http://127.0.0.1/uri”这样。
其中的/path就称为虚拟路径,虚拟给用户的,后端没有真正的/path路径,这里要特别注意”proxy_pass http://127.0.0.1/”最后的”/”,如果没有这个”/”那么访问就会出现404,因为你没有给proxy_pass定义URI,所以不存在将规范化以后的请求路径(原始请求URI)与location配置中的路径的匹配部分将被替换为proxy_pass指令中定义的URI这一说法,切记。Nginx实现虚拟路径代理
注意
当使用一个正则表达式(~或~*)指定localtion时,在这种情况下,proxy_pass应该是一个没有URI的指令,如果指定了URI,那么代理到后端时,URI会被去掉,从而变成了http://127.0.0.1/some/path,也就是说原始访问URI不会做任何改变传送到后端。
还有一种情况,当URI使用rwrite重写指令后,在这种情况下,proxy_pass应该是一个没有URI的指令,如果指定了URI,那么代理到后端时,URI会被去掉,从而变成了http://127.0.0.1/some/path。
rewrite /name/([^/]+) /users?name=$1 break;
最后,这种以代理的工作方式,一般都会使用到Nginx upstream,以此来做负载均衡。这种情况下直接给定一个upstream的名称即可(需要先定义一个upstream),如下:
location / { upstream test{ 127.0.0.1:80; } proxy_pass http://test; }
13)proxy_next_upstream
Syntax: proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | non_idempotent | off ...; Default:proxy_next_upstream error timeout; Context:http, server, location
当你使用Nginx proxy代理时,如果是代理到后端是使用upstream,那么这个指令就是指定在何种情况下,一个失败的请求应该被发送到下一台后端服务器,有如下指令:
error – 和后端服务器建立连接时,或者向后端服务器发送请求时,或者从后端服务器读取响应时,出现错误;
timeout – 和后端服务器建立连接时,或者向后端服务器发送请求时,或者从后端服务器读取响应时,出现超时;
invalid_header – 后端服务器返回空响应或者非法响应头;
http_500 – 后端服务器返回的响应状态码为500;
http_502 – 后端服务器返回的响应状态码为502;
http_503 – 后端服务器返回的响应状态码为503;
http_504 – 后端服务器返回的响应状态码为504;
http_404 – 后端服务器返回的响应状态码为404;
off – 关闭proxy_next_upstream功能—出错就选择另一台上游服务器再次转发。
需要理解一点的是,只有在没有向客户端发送任何数据以前,将请求转给下一台后端服务器才是可行的。也就是说,如果在传输响应到客户端时出现错误或者超时,这类错误是不可能恢复的。
另外Nginx1.7开始提供了将请求传递给下一台服务器可以通过重试的次数和时间进行限制。
14)proxy_next_upstream_timeout
Syntax: proxy_next_upstream_timeout time; Default:proxy_next_upstream_timeout 0; Context:http, server, location This directive appeared in version 1.7.5.
限制了重试请求可以被传递给下一台服务器的时间,默认值为0将关闭这一限制。
15)proxy_next_upstream_tries
Syntax: proxy_next_upstream_tries number; Default:proxy_next_upstream_tries 0; Context:http, server, location This directive appeared in version 1.7.5.
限制了重试请求可以被传递给下一台服务器的次数,默认值为0将关闭这一限制。
16)proxy_read_timeout
Syntax: proxy_read_timeout time; Default:proxy_read_timeout 60s; Context:http, server, location
定义从后端服务器读取(接收)数据的超时时间(Nginx从客户端接收到请求,然后把数据包转发到后端服务器,后端服务器处理完请求后返回给Nginx服务器,Nginx接收后端数据包称为一次read),此超时是指相邻两次读操作之间的最长时间间隔,而不是整个响应传输完成的最长时间。如果后端服务器在超时时间段内没有传输任何数据,连接将被关闭。默认时间为60s,建议值为2-4s。
17)proxy_send_timeout
Syntax: proxy_send_timeout time; Default:proxy_send_timeout 60s; Context:http, server, location
定义向后端服务器发送一次数据包的超时时间(Nginx从客户端接收到请求,然后把数据包转发到后端服务器称为一次send),此超时是指相邻两次写操作之间的最长时间间隔,而不是整个请求传输完成的最长时间。
如果再向后端服务器发送数据包时,超过了超时时间的设置,那么连接将被关闭。默认时间为60s,建议值为2-4s。
18)proxy_set_header
Syntax: proxy_set_header field value; Default:proxy_set_header Host $proxy_host; proxy_set_header Connection close; Context:http, server, location
允许重新定义或者添加发往后端服务器的请求头。value可以包含文本、变量或者它们的组合。 当且仅当当前配置级别中没有定义proxy_set_header指令时,会从上面的级别继承配置。 默认情况下,只有两个请求头会被重新定义:
proxy_set_header Host $proxy_host; proxy_set_header Connection close;
如果不想改变请求头“Host”的值,可以这样来设置:
proxy_set_header Host $http_host;
但是,如果客户端请求头中没有携带这个头部,那么传递到后端服务器的请求也不含这个头部。 这种情况下,更好的方式是使用$host变量——它的值在请求包含“Host”请求头时为“Host”字段的值,在请求未携带“Host”请求头时为虚拟主机的主域名:
proxy_set_header Host $host;
此外,服务器名可以和后端服务器的端口一起传送:
proxy_set_header Host $host:$proxy_port;
如果某个请求头的值为空,那么这个请求头将不会传送给后端服务器:
proxy_set_header Accept-Encoding "";
proxy_add_x_forwarded_for内置变量,将proxy_add_x_forwarded_for内置变量,将remote_addr变量值添加在客户端“X-Forwarded-For”请求头的后面,并以逗号分隔。
如果客户端请求未携带“X-Forwarded-For”请求头,proxy_add_x_forwarded_for变量值将与proxy_add_x_forwarded_for变量值将与remote_addr变量相同。
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
19)proxy_pass_header
Syntax: proxy_pass_header field; Default:— Context:http, server, location
允许指定跳过某些字段从代理服务器到客户端,一般用在CDN中传回来的字段信息,但不需要传回到后端服务器,就可以使用proxy_pass_header指令跳过。
20)proxy_redirect
Syntax: proxy_redirect default; proxy_redirect off; proxy_redirect redirect replacement; Default:proxy_redirect default; Context:http, server, location
设置后端服务器“Location”响应头和“Refresh”响应头的替换文本。 假设后端服务器返回的响应头是 “Location: http://localhost:8000/two/some/uri/”,那么指令
proxy_redirect http://localhost:8000/two/ http://frontend/one/;
将把字符串改写为 “Location: http://frontend/one/some/uri/”。
实例
upstream appservers { zone appservers 64k; #默认权重为1 server appserv1.example.com weight=5; server appserv2.example.com:8080 fail_timeout=5s slow_start=30s; server 192.0.2.1 max_fails=3; server reserve1.example.com:8080 backup; server reserve2.example.com:8080 backup; } server { location / { proxy_pass http://appservers; health_check; } location /upstream_conf { upstream_conf; allow 127.0.0.1; deny all; } }
参数解释:
1.weight=number
设定服务器的权重,默认是1。
2.max_fails=number
设定Nginx与服务器通信的尝试失败的次数。
3.fail_timeout=time
设定
默认情况下,该超时时间是10秒。backup标记为备用服务器。当主服务器不可用以后,请求会被传给这些服务器。
4.down
标记服务器永久不可用,可以跟ip_hash指令一起使用。
5.route=string
设置服务器路由名称。
后面会分享更多devops和DBA方面的内容,感兴趣的朋友可以关注一下~