利用proxy_pass可以将请求代理到后端服务器,上一节中的配置示例都指向同一台服务器,如果需要指向多台服务器就要用到ngx_http_upstream_module。它为反向代理提供了负载均衡及故障转移等重要功能。
先来看一个简单的版本:
指令:upstream
语法:upstream name {...}
环境:http
含义:定义一组HTTP服务器,这些服务器可以监听不同的端口,以及TCP和UNIX 套接字。在同一个upstream中可以混合使用不同的端口、TCP和UNIX 套接字。
指令:server
语法:server address [parameters];
环境:upstream
含义:配置后端服务器,参数可以是不同的IP地址、端口号,甚至域名。
server指令拥有丰富的参数,其参数说明见表3-4。
表3-4 server指令参数说明
续表
如果在前面的配置示例中出现了超过请求失败次数的服务器,下面这些参数可以用来对这些服务器进行配置:proxy_next_upstream、fastcgi_next_upstream、uwsgi_next_upstream、scgi_next_upstream、memcached_next_upstream和grpc_next_upstream。
下面用最常见的proxy_next_upstream为例进行说明。
指令:proxy_next_upstream
语法:proxy_next_upstream error|timeout|invalid_header|http_500|http_502|http_503 |http_504|http_403|http_404|http_429|non_idempotent|off ...;
默认值:proxy_next_upstream error timeout;
环境:http、server、location
含义:定义转发条件,当请求返回Nginx时,如果HTTP状态满足proxy_next_upstream设置的条件,就会触发Nginx将请求重新转发到下一台后端服务器,并累加出现此状态的服务器的失败次数(当超过max_fails和fail_timeout的值时就会设置此服务器为不可用)。如果设置为off,则表示关闭此功能。
指令:proxy_next_upstream_tries
语法:proxy_next_upstream_tries number;
默认值:proxy_next_upstream_tries 0;
环境:http、server、location
含义:定义尝试请求的次数,达到次数上限后就停止转发,并将请求内容返回客户端。
指令:proxy_next_upstream_timeout
语法:proxy_next_upstream_timeout time;
默认值:proxy_next_upstream_timeout 0;
环境:http、server、location
含义:限制尝试请求的超时时间,如果第一次请求失败,下一次请求就会被此参数值控制。若设置为 0,则表示无超时时间,但尝试的请求仍会受到 proxy_read_timeout、proxy_send_timeout、proxy_connect_timeout的影响。
注意: 通过这些配置,可以在后端服务器的某些节点出现请求异常时,快速做出故障切换的操作,从而屏蔽这些异常的请求。但是这存在一种隐患,即如果proxy_next_upstream_tries设置的值比较大,且proxy_next_upstream也设置了很多状态,当发生大面积异常时,重试不断累加,可能会导致请求反复向多个服务器发送,这样会给后端服务器带来更大的压力。
Nginx不仅支持代理多台后端服务器,也支持各种负载均衡模式,负载均衡在upstream的配置环境内设置(默认根据权重轮询)。负载均衡指令见表3-5。
表3-5 负载均衡指令
缓存系统是减少后端服务压力的重要组件,常见的 HTTP缓存系统有 Nginx的proxy_cache、varnish、squid。如果通过反向代理去获取缓存数据,一般需要使用hash分片,以避免URL的请求随机进入缓存系统的某个分片,导致缓存命中率低、后端服务器压力上升。
基于URL缓存的服务配置一般如下所示,相同的URL(包含参数)会进入相同的后端缓存系统。
注意:
· 增减节点会导致hash重新计算,因此增减节点最好选择在服务的低峰期进行。
· 在缓存系统上使用max_fails不一定是最好的选择,但一旦使用请确保proxy_next_upstream的合理性,尽量不要配置各种HTTP状态码,因为缓存系统代理的是后端服务,当后端服务异常时会将错误的状态码返回给Nginx,这样会让Nginx以为缓存系统出了问题,从而将缓存节点当作失败的节点,停止分流。
缓存系统的故障转移应该只以存活检查方式(一般指检查缓存系统的端口是否存活,以及固定检查一个接口是否能返回正常的响应)为主。可以结合健康检测功能,或者动态剔除异常缓存节点的功能来使用,详细介绍请看后续章节。
在Nginx中,使用upstream进行后端访问默认用的是短连接,但这会增加网络资源的消耗。可以通过配置长连接,来减少因建立连接产生的开销、提升性能。和长连接有关的配置示例如下:
长连接配置指令说明见表3-6。
表3-6 长连接配置指令说明
注意: 如果没有添加长连接,在压力测试(以下简称压测)环境中,可能会出现这样的情景:当压测达到一定的QPS(Query Per Second,每秒查询率)后,Nginx服务器突然“卡死”,QPS直接降到几乎为0,但是压测并没有停;几分钟后又会自动恢复,然后再压测一段时间后,QPS 又会突然降到接近于0。这种情况就要考虑是不是timewait的状态过多了。
proxy_pass可以直接将域名代理到后端服务器上,请求前会先解析出IP地址,例如:
反复的DNS(Domain Name System,域名系统)解析会影响请求的速度,并且如果出现连接DNS服务器超时的情况,可能会导致请求无法发送,这里需要用DNS缓存来解决这个问题,示例代码如下:
resolver指令说明见表3-7。
表3-7 resolver指令说明
注意: 解析DNS后,通过set $upstream_host test2.zhe800.com的方式,将获取的IP地址再赋值给proxy_pass,这是为了让Nginx重新去解析DNS中的IP地址。利用valid的配置,可以减少DNS的解析次数,从而提高请求的效率。当然对DNS缓存时间的控制也要有度,避免出现DNS切换IP地址后,Nginx无法快速切换到新IP地址的情况。
如果需要在upstream内部对域名的配置进行解析,使用Nginx的开源版会受到一些限制,因为此功能被放到了商业版中,需要和zone的功能配合使用。