Nginx限流配置

147次阅读
没有评论

概述:

当我们的程序上线之后,会遇到请求量太大,或者恶意请求的问题,这样我们就需要对我们的程序进行限流。当然限流的操作有很多种,可以使用后端程序进行限流,也可以使用Nginx进行限流。具体的限流方案根据项目情况而定,这里我推荐使用Nginx进行限流,因为使用后端程序进行限流会消耗我们的后端资源。下面讲解具体操作步骤

第一步:配置Nginx

这里配置的是nginx.conf文件

  http {
    keepalive_timeout 75s;
    sendfile        on; #当nginx代理的是静态文件服务的时候,打开这个会提升性能
    tcp_nopush      on; #启用linux上的tcp_cork套接字选项,它只能配合sendfile一起使用
    # 根据ip限制速率,zone=名称:(桶)大小,放不下会丢弃请求,rate=同IP 5次/s ,平均200ms/次
    limit_req_zone $binary_remote_addr zone=ratelimit:30m rate=5r/s;
	server {
		listen      80; #监听端口
		server_name  my.domain.cn;  #域名
		charset utf-8; #设置字符集
		root   /opt/web/order/dist;  #vue项目路径
		location / {
			#burst是突发流量先不拒绝,单ip允许额外5个请求放入队列,nodelay降低突发流量排队,只要队列里有数据,就马上分配worker处理
 			limit_req zone=ratelimit burst=5 nodelay;
 			#当限制时,返回的状态码503 不可访问
 	                limit_conn_status 503; 
 			index  /index.html;
			try_files $uri $uri/ /index.html;
	    }
	}
  }

第二步:配置详解

1、limit_req_zone 用于设置限流和共享内存区域的参数,格式为:limit_req_zone key zone rate。

2、$binary_remote_addr 是 nginx 中的变量,表示基于 remote_addr(客户端IP) 来做限流,binary_ 是二进制存储。使用 $binary_remote_addr 而不是 $remote_addr 是因为二进制存储可以压缩内存占用量。 $remote_addr 变量的大小从7到15个字节不等,而 $binary_remote_addr变量的大小对于 IPv4 始终为4个字节,对于 IPv6 地址则为16个字节。

3、zone:定义共享内存区来存储访问信息,访问信息包括每个 IP 地址状态和访问受限请求 URL 的频率等。zone 的定义又分为两个部分:由 zone= 关键字标识的区域名称,以及冒号后面的区域大小。myLimit:10m 表示一个大小为10M,名字为 myLimit 的内存区域。1M 能存储16000个 IP 地址的访问信息,myLimit 大概可以存储约160000个地址。nginx 创建新记录的时候,会移除前60秒内没有被使用的记录,如果释放的空间还是存储不了新的记录,会返回503的状态码。

4、rate:设置最大的访问速率。rate=2r/s(为了好模拟,rate 设置的值比较小),表示每秒最多处理 2 个请求。事实上 nginx 是以毫秒为粒度追踪请求的,rate=2r/s 实际上是每500毫秒1个请求,也就是说,上一个请求完成后,如果500毫秒内还有请求到达,这些请求会被拒绝(默认返回503,如果想修改返回值,可以设置limit_req_status)。

这里需要注意的是Nginx是根据毫秒来定义请求限制的,比如我一秒允许两个请求,那么第二次请求必须要在500ms之后,否则就会被限流

5、burst :表示在超过设定的访问速率后能额外处理的请求数。当 rate=2r/s 时,表示每500ms 可以处理一个请求。burst=5时,如果同时有10个请求到达,nginx 会处理第1个请求,剩余9个请求中,会有5个被放入队列,剩余的4个请求会直接被拒绝。然后每隔500ms从队列中获取一个请求进行处理,此时如果后面继续有请求进来,如果队列中的请求数目超过了5,会被拒绝,不足5的时候会添加到队列中进行等待。

6、nodelay :表示不延迟。设置 nodelay 后,第一个到达的请求和队列中的请求会立即进行处理,不会出现等待的请求。

7、limit_req:这个对应的是第一点的配置,ratelimit对应的也是第一点的zone=ratelimit。

8、limit_conn_status:定义触发限流时返回的状态码。

所以以上配置就是当80端口进来的时候,所有的请求都会被限制为同一个ip,1秒只能五次,同时缓存了五次,并且不延迟,也就是我们可以在一秒内任何时候都可以请求五次,并且及时返回结果;

番外篇:配置ip白名单、ip连接数

ip白名单:

geo $limit {
    default 1;
    10.0.0.0/8 0;
    192.168.0.0/24 0;
}

map $limit $limit_key {
    0 "";
    1 $binary_remote_addr;
}

limit_req_zone $limit_key zone=mylimit:10m rate=2r/s;

解释说明:geo 指令可以根据 IP 创建变量 $limit。$limit 的默认值是1,如果匹配到了下面的 IP,则返回对应的值(这里返回的是0)。之后通过 map 指令,将 $limit 的值映射为 $limit_key:在白名单内的,$limit_key 为空字符串,不在白名单内的,则为 $binary_remote_addr。当limit_req_zone指令的第一个参数是一个空字符串,限制不起作用,因此白名单的 IP 地址(在10.0.0.0/8和192.168.0.0/24子网中)没有被限制,其它 IP 地址都被限制为 2r/s。
限制ip连接数量:

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
server {
    location ~* \.(html)$ {
        limit_conn perip 10;
        limit_conn perserver 100;
    }
} 

 
解释说明:imit_conn perip 10:key 是 $binary_remote_addr,表示限制单个IP同时最多能持有10个连接。
limit_conn perserver 100: key 是 $server_name,表示虚拟主机(server) 同时能处理并发连接的总数为100。
需要注意的是:只有当 request header 被后端server处理后,这个连接才进行计数。

正文完
 
评论(没有评论)