NGINX限制对HTTP资源的访问

文章目录

        • 介绍
        • 限制连接数
        • 限制请求速率
          • 测试请求速率限制
          • 处理过多的请求
          • 延迟过多的请求
          • 同步许多共享内存区域的内容
        • 限制带宽
          • 动态带宽控制
        • 参考文档

    本文介绍了如何设置连接请求的最大数量,或从服务器下载内容的最大速率。

介绍

    使用NGINX和NGINX Plus,可以限制:

  • 每个键值的连接数(例如,每个IP地址)
  • 每个键值的请求率(在一秒钟或一分钟内允许处理的请求数)
  • 连接的下载速度

    请注意,可以在NAT设备后面共享IP地址,因此应谨慎使用IP地址限制。

限制连接数

    为了限制连接数:

  1. 使用limit_conn_zone指令定义key并设置共享内存区域的参数(工作进程将使用此区域共享键值计数器)。作为第一个参数,指定表达式作为键。在第二个参数区域中,指定区域的名称及其大小
limit_conn_zone $binary_remote_addr zone=addr:10m;
  1. 使用 limit_conn 指令在 location{},server{},或 http{}上下文中应用限制。将共享内存区域的名称指定为第一个参数,将每个键允许的连接数指定为第二个参数
location /download/ {
     limit_conn addr 1;
}

    因为 $binary_remote_addr 变量用作键,所以连接数受IP地址限制。
    限制给定服务器的连接数的另一种方法是使用 $server_name 变量:

http {
    limit_conn_zone $server_name zone=servers:10m;

    server {
        limit_conn servers 1000;
    }
}

限制请求速率

    速率限制可用于防止DDoS攻击,或防止上游服务器同时被太多请求淹没。该方法基于leaky bucket算法:请求以各种速率到达存储桶,并以固定速率离开存储桶。
    在使用速率限制之前,您需要配置“泄漏桶”的全局参数:

  • key - 用于区分一个客户端与另一个客户端的参数,通常是一个变量
  • 共享内存区域 - 保留这些键的状态的区域的名称和大小(“泄漏存储桶”)
  • rate - 以每秒请求数(r/s)或每分钟请求数(r/m)(“漏水桶排水”)指定的请求速率限制。每分钟请求数用于指定小于每秒一个请求的速率。

    这些参数是通过 limit_req_zone 指令设置的。该指令是在 http{} 级别定义的,这种方法允许将不同的区域和请求溢出参数应用于不同的上下文:

http {
    #...
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
}

    使用此配置,将one创建大小为10 MB 的共享内存区域。该区域保留使用 $binary_remote_addr 变量设置的客户端IP地址的状态。注意,与 $remote_addr 同时拥有客户端的IP地址相比,$binary_remote_addr 拥有IP地址的二进制表示,后者更短。
    使用以下数据可以计算共享内存区域的最佳大小:对于IPv4地址,$binary_remote_addr 值的大小为4字节,存储状态在64位平台上占用64字节。因此,大约16000个IP地址的状态信息占据了分区的1兆字节。
    如果NGINX需要添加新条目时存储空间耗尽,它将删除最旧的条目。如果释放的空间仍然不足以容纳新记录,NGINX将返回状态代码503 Service Unavailable。状态代码可以用limit_req_status指令重新定义。
    一旦设置了zone区域,您就可以使用NGINX配置限制任何请求,在server {},location {},或 http {}上下文中使用 limit_req 进行设置。

http {
    #...

    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    server {
        #...

        location /search/ {
            limit_req zone=one;
        }
    }
}

    使用此配置,NGINX将在 /search/ 位置内每秒处理不超过1个请求。延迟处理这些请求的方式使得总速率不大于指定速率。如果请求数超过指定的速率,NGINX将延迟处理这些请求,直到“bucket”(共享内存区域one)满为止。如果请求到达后,存储桶已满,NGINX将返回503 Service Unavailable错误(如果没有使用limit_req_status重新定义)。

测试请求速率限制

    在配置实际速率限制之前,可以尝试不限制请求处理速率的“空运行”模式。但是,过多的此类请求仍在共享内存区域中进行处理并记录。可以使用 limit_req_dry_run 指令启用“空运行”模式:

http {
    #...

    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    server {
        #...

        location /search/ {
            limit_req zone=one;
            limit_req_dry_run on;
        }
    }
}

    每一个超过规定速率限制的请求都将被记录为“空运行”标记:

2019/09/03 10:28:45 [error] 142#142: *13246 limiting requests, dry run, excess: 1.000 by zone "one", client: 172.19.0.1, server: www.example.com, request: "GET / HTTP/1.0", host: "www.example.com:80"
处理过多的请求

    请求被限制为符合limit_req_zone指令中定义的速率。如果请求数超过指定的速率,并且共享内存区域已满,NGINX将响应一个错误。由于流量趋向于突发性,因此在流量突发期间响应客户端请求返回错误不是最好的情况。
    NGINX中的此类过多请求可以被缓冲和处理。limit_req指令的burst参数设置等待以指定速率处理的过多请求的最大数量:

http {
    #...

    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    server {
        #...

        location /search/ {
            limit_req zone=one burst=5;
        }
    }
}

    使用此配置,如果请求速率超过每秒1个请求,则超出速率的请求将被放入区域one。当区域已满时,将对过多的请求进行排队(burst),此队列的大小为5个请求。队列中的请求处理将以不大于指定速率的方式延迟。超过突发限制的请求将被拒绝,并返回503错误。
    如果在流量突发期间不需要延迟请求,请添加nodelay参数:

http {
    #...

    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    server {
        #...

        location /search/ {
            limit_req zone=one burst=5 nodelay;
        }
    }
}

    使用此配置,在burst限制内的过多请求将立即被服务,而不管指定的速率如何,超过突发限制的请求将被拒绝,并出现503错误。

延迟过多的请求

    处理过多请求的另一种方法是毫不延迟地服务其中一些请求,然后应用速率限制,直到过多请求将被拒绝为止。
    这可以通过delay和burst参数来实现。delay参数定义了延迟过多请求以符合定义的速率限制的时间点:

http {
    #...

    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    server {
        #...

        location /search/ {
            limit_req zone=one burst=5 delay=3;
        }
    }
}

    使用此配置时,前3个请求(delay)会立即传递,后2个请求(burst- delay)会以总速率不超过指定速率的方式被延迟,因为超出了总突发大小,其他多余的请求将被拒绝,后续请求将被延迟。

同步许多共享内存区域的内容

    如果您的计算机群集具有多个NGINX实例,并且这些实例使用 limit_req 方法,则可以在以下条件下同步其共享内存区域的内容:

  • 为每个实例配置了zone_sync功能
  • 在limit_req_zone指令中为每个实例设置的共享内存区域具有相同的名称
  • 为每个实例指定limit_req_zone指令的sync参数:
http  { 
    #... 
    limit_req_zone  $ binary_remote_addr  zone = one:10m  rate = 1r / s  sync ; 
}

限制带宽

    要限制每个连接的带宽,请使用 limit_rate 指令:

location /download/ {
    limit_rate 50k;
}

    通过这种设置,客户端将能够以每秒50k字节的最大速度通过单个连接下载内容。但是,客户端可以打开多个连接。因此,如果目标是防止下载速度超过指定值,那么连接的数量也应该受到限制。例如,每个IP地址一个连接(如果使用上面指定的共享内存区域):

location /download/ {
    limit_conn addr 1;
    limit_rate 50k;
}

    若要仅在客户端下载一定数量的数据后实施限制,请使用limit_rate_after指令。允许客户端快速下载一定数量的数据(例如,文件头-电影索引)并限制下载其余数据的速率(使用户观看电影而不是下载)可能是合理的。

limit_rate_after 500k;
limit_rate       20k;

    下面的示例显示了用于限制连接数和带宽的组合配置。允许的最大连接数被设置为每个客户端地址的5个连接,这符合大多数常见情况,因为现代浏览器通常一次打开3个连接。同时,提供下载服务的location只允许一个连接:

http {
    limit_conn_zone $binary_remote_address zone=addr:10m

    server {
        root /www/data;
        limit_conn addr 5;

        location / {
        }

        location /download/ {
            limit_conn       addr 1;
            limit_rate_after 1m;
            limit_rate       50k;
        }
    }
}
动态带宽控制

    limit_rate值也可以指定为变量 – 这启用了动态带宽用例,例如,允许现代浏览器使用更高的带宽限制:

map $ssl_protocol $response_rate {
    "TLSv1.1" 10k;
    "TLSv1.2" 100k;
    "TLSv1.3" 1000k;
}

server {
    listen 443 ssl;
    ssl_protocols       TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;

    location / {
        limit_rate       $response_rate; # Limit bandwidth based on TLS version
        limit_rate_after 512;      # Apply limit after headers have been sent
        proxy_pass       http://my_backend;
    }
}

参考文档

https://docs.nginx.com/nginx/admin-guide/security-controls/controlling-access-proxied-http/

你可能感兴趣的:(Nginx)