nginx的反向代理
反向代理是nginx的主要功能之一,平时我们在使用Nginx的时候一般就是用其性能高效的反向代理功能。
为了线上环境中的降级和服务替换,nginx的upstream模块提供了通用的参数。
通用的参数有(不论是round-robin,还是hash)
- backup:指定当前server为备份服务,当且仅当所有的非备份服务器不可用的时候,请求才会转发到该server。
- down:标识某台服务已经下线,不在服务。
round-robin算法
round-robin 轮询是nginx反向代理的默认使用的算法。
指定上游服务地址的upstream模块。
指令。
upstream backend1{
server 192.168.0.2:80 weight=1 max_fails=3 fail_timeout=30s;
}
- weight: 服务器的访问权重
- max_conns: server的最大并发连接数字,仅作用于单worker进程。默认是0,表示没有限制。
- max_fails: 在fail_timeout 时间段内,最大的失败次数,当达到最大的失败次数时,会在fail_timeout 秒内这台server 不会再次选中。
- fail_timeout:单位为秒,默认是10s。具有两个功能(配合max_fails 使用)如上所述。
对上游服务使用keepalive长连接
通过复用tcp连接,降低nginx与上游服务器的建立、关闭连接的消耗,提高吞吐量的同时降低时延。
对上游连接设定的http头部(因为http1.0 不支持keepalive)
proxy_http_version 1.1;
proxy_set_header Connection "";
- keepalive connections:向一组upstream最多保持多少个空闲的tcp连接用来keepalive请求。Nginx 和后端的长连接不够用时 Nginx 会新建连接来处理新的请求(是 Nginx 每个 worker 连接后端的最大长连接数,而不是整个 Nginx 的)
- keepalive_requests number:1.15.3新增指令。一条keepalive上最多跑多少条请求。
- keepalive_timeout:1.15.3新增指令。一条tcp连接,超过多长时间没有请求的话,关闭tcp。
- resolver:当使用域名访问时,指定我们自己的dns服务器。
- resolver_timeout:dns超时时间。
测试
如下是我nginx的配置。
upstream backend {
keepalive 32;
server 192.168.199.214:8081 weight=1 max_fails=2 fail_timeout=5s;
server 192.168.199.214:8082 weight=1 max_fails=2 fail_timeout=5s;
}
server {
listen 80;
server_name app.prometheus.wjx;
location / {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://backend;
}
}
一台后端挂了后,nginx如何处理
当我将8081 的这台机器挂掉后。
从tcp层面会有RST,也就是http无法再用这条tcp连接。所以当然http请求是无法发送到8081这台机器,nginx会默认将请求发往下一台server 8082。tcp建立通了,才会有http请求过去,也就是说nginx是有高效的错误处理能力的。当配置的5s后(不一定就5s),nginx会再试8081 端的server,5s后再有请求,会重新尝试与8081建立tcp连接。
抓包得出
keepalive 对nginx和后端的影响
- 当keepalive配置只有1,压力测试
ab -n 10 -c 2 http://localhost/
wireshark抓包
从上图可以看出,其实只有一个keepalive连接,其他的还是使用了短连接。
-
当keepalive为2048时,压力测试
只建立了两个tcp连接,分别是两个后端server的。也就是每个server一条连接,传输了所有的数据。
wireshark抓包 -
不开启keepalive。压力测试
开启keepalive的时候,nginx的timewait达到了 14000+个。而server端的timewait几乎为0。(因为开启时,server会认为这是一个长连接,不会主动关闭,而不开启的话,server会在一次请求结束后主动关闭长连接)
不开启keepalive的时候,nginx的timewait为1000+个,而server端为900+个。
而看看抓包情况。。。满屏的tcp syn握手包。
wireshark握手包
least_conn 算法
这个算法是由upstream_least_conn 模块提供的。功能是从所有的上游服务中找出并发连接数最少的一个,将请求转发到它。
一般很少用到,当所有的server的连接都相同的时候,该算法会退化成round_robin算法。
upstream模块提供的变量
变量 | 作用 |
---|---|
upstream_addr | 上游服务的ip地址+port |
upstream_connect_time | 与上游服务建立连接消耗的时间 |
upstream_header_time | 接收上游服务发回响应的头部消耗的时间 |
upstream_response_time | 接收上游服务响应消耗的时间 |
upstream_bytes_received | 从上游服务接收到的响应长度 |
upstream_response_length | 从上游服务返回的响应包体的长度 |
upstream_status | 上游服务的返回的状态码未连接上是502 |
proxy 模块
proxy_pass 是反向代理中最重要的一个模块。
其大体流程如图所示。
proxy_pass.png
proxy_request_buffering 和 proxy_buffering 为 off 时才会边读包体边发送
根据指令生成发往上游的请求行
- proxy_method method : 将请求方法
- proxy_http_version 1.0|1.1 : 更改http的version(keepalive就需要1.1)
- proxy_set_header :添加头部
- proxy_pass_request_headers on|off :是否将用户请求的包头发给上游(默认当然是发的)。
- proxy_pass_request_body on|off:是否将用户请求包体发给上游(默认当然是发的)。
- proxy_set_body value:添加包体
接收客户端请求的包体
- proxy_request_buffering on|off 上面已经说了off的话会边收包体边发。
- on:1.客户端网速慢。2.上游服务并发处理能力低。3.适应高吞吐场景。
- off:1.更及时的响应。2.降低nginx读写磁盘的消耗。 3.一旦开始发送 proxy_next_upstream 功能失败。
- client_body_buffer_size size:接收请求的header时,为接收到包体分配内存。默认8k或16k。
- 若接收头部时已经接收完全部包体,则不分配。
- 若剩余待接收包体长度小于client_body_buffer_size, 则分配所需大小
- client_max_body_size size :允许请求包体最大长度的限制,默认是1M
- client_body_temp_path path:临时文件的路径(放请求body的)
- client_body_in_file_only on | clean | off:默认是off 的。一般是请求body写到文件中,on的话是永久保存的,一般用于定位问题。
- client_body_timeout time:读取包体时超时,则返回408错误。
nginx与上游服务建立连接
- proxy_connect_timeout time :与上游服务建立tcp连接的超时时间。超时后会生成502。(默认60s)
- proxy_socket_keepalive on|off:当设置为on时,会使用操作系统的tcp去操作tcp keepalive。
- keepalive:有几个keepalive。
- keepalive_requests:连接最多执行多少个http请求。
- proxy_ignore_client_abort on|off:当client关闭连接,是否关闭与upstream关闭(默认是off的,on的话对上游压力很大)
- proxy_send_timeout:向upstream发送请求的超时时间。
nginx接收upstream的响应
- proxy_buffer_size size:
- proxy_buffering on|off:off为边发边收。
- proxy_buffers number size:当不是边发边收的情况下就需要将包体写到磁盘中,但是磁盘还是比较慢的。如果这里指定了buffer,小文件(buffer能存放下)就不会写文件了。
- proxy_max_temp_file_size size:限制upstream回返的包体写入磁盘的最大值。默认是1G。
- proxy_temp_file_write_size size:限制每一次向临时磁盘文件写入的字节数。
- proxy_temp_path path [level1 [level2 [level3]]]:临时文件写入的文件目录。
- proxy_busy_buffers_size size:及时转发包体,先向客户端转发接收到的size字节。
- proxy_read_timeout time:读取超时时间。
- proxy_limit_rate rate :限速读取上游的响应。
上游出现失败时的容错方案
当upstream的上游服务返回失败时的处理方法。
- proxy_next_upstream
当出现错误,超时,错误头部,指定的返回码。 - proxy_next_upstream_timeout 超时时间
- proxy_next_upstream-tries 重试次数
location / {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_connect_timeout 1s;
proxy_next_upstream off;
proxy_pass http://backend;
}
proxy_next_upsteam
- off :错误了还是返回。
- error:屏蔽错误,502。
- http_500:500 错误会被屏蔽