在nginx中为了避免因为后端服务器异常带来的接口不可用,nginx提供了主动健康检测模块nginx_upstream_check_module(淘宝开源提供)和被动检测ngx_http_upstream_module,我们先说下被动检测ngx_http_upstream_module,可以在upstream指令块中的server子指令参数max_fails、fail_timeout来进行被动检测,如:

upstream backend {
    server 127.0.0.1:8080 weight=1 max_fails=2 fail_timeout=10s;
    server 127.0.0.1:8081 weight=1 max_fails=2 fail_timeout=10s;
}

   max_fails=2的意思是设定Nginx与服务器通信的尝试失败的次数。在fail_timeout参数定义的时间段内,如果失败的次数达到此值,Nginx就认为服务器不可用。在下一个fail_timeout时间段,服务器不会再被尝试。失败的尝试次数默认是1。设为0就会停止统计尝试次数,认为服务器是一直可用的。

   fail_timeout=10s是设定服务器被认为不可用的时间段以及统计失败尝试次数的时间段。在这段时间中,服务器失败次数达到指定的尝试次数,服务器就被认为不可用。默认情况下,该超时时间是10秒。
主动健康检测模块nginx_upstream_check_module使用方式如下:

upstream cluster {
    # simple round-robin
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
    check interval=5000 rise=1 fall=3 timeout=4000;
    #check_http_send "HEAD / HTTP/1.0\r\n\r\n";
    #check_http_expect_alive http_2xx http_3xx;
}

其操作是如果后端服务器不可用,则把这台服务器移除负载均衡轮循集群,所有的请求不往这台服务器上转发,待这台服务器恢复正常后,再把这台加入到负载均衡集群。更多相关内容参考Nginx实用插件。

当发现后端服务器不可用的时候,我们需要进行故障转移,nginx也通过ngx_http_proxy_module模块提供了对故障转移的支持,设置的简单命令有:

   1.proxy_next_upstream

      在尚未向客户端发送任何内容的情况下才能将请求传递给下一个服务器。也就是说,如果在传输响应的过程中发生错误或超时,则无法进行故障转移。一个请求传递给下一个服务时,还可以通过限制重试次数、等待时间。具体参数配置可以参考http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream

   2.proxy_next_upstream_timeout

      限制请求可以传递到下一个服务器的时间。默认为0,表示关闭限制。

   3.proxy_next_upstream_tries

      限制将请求传递到下一个服务器的可能尝试次数 。默认为0,表示关闭限制。

当进行故障转移的时候,本来被转移到的服务器原来的并发数是完全可以承受的,但是当把出现故障后的服务器的并发数转移过来后,服务器就可能导致并发异常出现故障,以此类推就容易造成雪崩的现象,nginx为了防止出现雪崩,可以通过设置参数来预防雪崩的现象:

   1.proxy_read_timeout

      定义从代理服务器读取响应的超时。仅在两个连续的读操作之间设置超时,而不是为整个响应的传输。如果代理服务器在此时间内未传输任何内容,则关闭连接。默认60s。可以在http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_read_timeout 看到说明。

   2.max_conns参数

      设置upstream中server指令的max_conns参数来进行控制每台服务器能够处理的最大的连接数。

为了防止用户访问速度过快,Nginx中可以通过请求限制模块ngx_http_limit_req_module的指令来控制客户端的请求速率。使用“漏桶”算法,限制指定Key的请求处理速率,特别是从一个单一的IP地址的请求的处理速率。

http {
	limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
	limit_req_zone $server_name zone=preserver:10m rate=10r/s;
	server {
		location /search/ {
			limit_req zone=one burst=5;
			limit_req zone=perserver burst=10; 
		} 
	} 
}

上面的例子通过定义内存空间块:

   限制单个IP平均每秒允许不超过1个请求,突发不超过5个请求。

   整个虚拟服务,平均每秒不允许超过10个,突发不超过10个请求。
常用的命令如下:
   

指令

作用

默认值

limit_conn

设置共享内存区域和给定键值的最大允许连接数。超过此限制时, 服务器将返回 错误 以回复请求。

-

limit_conn_log_level

为服务器限制连接数的情况设置所需的日志记录级别

error

limit_conn_status

设置要响应拒绝的请求而返回的状态代码

503

limit_conn_zone

设置共享内存区域的参数,该区域将保留各种键的状态。特别是, 状态包括当前的连接数。该key可以包含文本,变量,他们的组合。 具有空键值的请求不计算在内。

-

我们除了可以限制访问速率,还可以限制连接数量,Nginx中通过ngx_http_limit_conn_module模块,来限制连接到nginx服务的数量。当然并非所有连接都被计算在内,只有当服务器正在处理请求并且已经读取了整个请求标头时,才会计算连接。

http {
	limit_conn_zone $binary_remote_addr zone=addr:10m;
	limit_conn_zone $server_name zone = perserver:10m;
	server {
		location /download/ {
			limit_conn addr 1;
			limit_conn perserver 100;
		} 
	}
}

上面的例子通过定义内存空间块:

   限制单个IP建立不超过1个连接。

   整个虚拟服务,不允许超过10个连接。

limit_conn 

   设置共享内存区域和给定键值的最大允许连接数。超过此限制时,服务器将返回错误以回复请求。

limit_conn_log_level 

   为服务器限制连接数的情况设置所需的日志记录级别,默认值error。

limit_conn_status 

   设置要响应拒绝的请求而返回的状态代码,默认值503。

limit_conn_zone

   设置共享内存区域的参数,该区域将保留各种键的状态。特别是,状态包括当前的连接数。该key可以包含文本,变量,他们的组合。具有空键值的请求不计算在内。

在一些视频网站中,针对非会员可能会有一些响应流量控制,nginx的ngx_http_core_module模块中对响应速率限制提供了支持

http {
	server {
		location /download/ {
			# 后续响应速率限制在500k
			limit_rate_after 500k;
			# 限制响应初始速率50k
			limit_rate 50k; 
		} 
	} 
}

爬虫作为一些公司抓取数据的工具,为了不影响系统的正常响应,都会对爬虫工具做出一些限定,在一些大型网站都会有类似下面的爬虫协议文档robots.txt,其放置在一个站点的根目录下,而且文件名必须全部小写,一词不差:

User-agent: * 这里的*代表的所有的搜索引擎种类,*是一个通配符
Allow: /cgi-bin/ 这里定义是允许爬寻cgi-bin目录下面的目录
Disallow: /admin/ 这里定义是禁止爬寻 admin 目录下面的内容
Disallow: /require/ 这里定义是禁止爬寻 require 目录下面的内容

nginx也提供了针对爬虫的限速,如下:

map $http_user_agent $agent {
	default "";
	~curl $http_user_agent;
	~*apachebench $http_user_agent;
	~*spider $http_user_agent;
	~*bot $http_user_agent;
	~*slurp $http_user_agent;
}
limit_conn_zone $agent zone=conn_ttlsa_com:10m;
limit_req_zone $agent zone=req_ttlsa_com:10m rate=1r/s;
location / {
	$agent limit_req zone=conn_ttlsa_com burst=5;
	limit_conn req_ttlsa_com 1;
	limit_rate 500k;
}

Map是nginx模块中用来映射变量的,根据每次请求$http_user_agent的内容进行子指令进行匹配,如果匹配成功,则将子指令右侧的值赋值给$agent变量。匹配不到则给默认值。示例中表示,根据客户端的操作系统浏览器工具等信息,匹配是否为curl、apachebench、spider、bot、slurp也就是爬虫程序相关的名称,这里采用了原有内容作为$agent的值。Limit_conn_zone、limit_req_zone则采用做为key来存储限制速率。 

当然我们还可以通过黑白名单的方式来阻止一些ip的访问,ngx_http_access_module模块,提供允许、拒绝指令来控制客户端能否访问服务。

location / {
	deny 192.168.1.1;
	allow 192.168.1.0/24;
	allow 10.1.1.0/16;
	allow 2001:0db8::/32;
	deny all;
}

allow

   允许某个ip或者一个 ip 段访问

deny

   禁止某个ip或者一个 ip 段访问

可以通过nginx_white_black_list 插件定义的黑白名单配置文件来进行控制客户端能否访问服务。

处在黑名单中的 ip 与网络,将无法访问 web 服务。

处在白名单中的 ip,访问 web 服务时,将不受 nginx 所有安全模块的限制。

支持动态黑名单(需要与 ngx_http_limit_req 配合)