Nginx限流配置(转载)

1、限流算法

令牌桶算法
13498144-26fa6023e301d96d.png
image.png

算法思想是:
a、令牌以固定速率产生,并缓存到令牌桶中;
b、令牌桶放满时,多余的令牌被丢弃;
c、请求要消耗等比例的令牌才能被处理;
d、令牌不够时,请求被缓存。

漏桶算法
13498144-593f61732b9638d5.png
image.png

算法思想是:
a、水(请求)从上方倒入水桶,从水桶下方流出(被处理),来不及流出的水存在水桶中(缓冲),以固定速率流出;
b、水桶满后水溢出(丢弃)。

这个算法的核心是:缓存请求、匀速处理、多余的请求直接丢弃。

相比漏桶算法,令牌桶算法不同之处在于它不但有一只“桶”,还有个队列,这个桶是用来存放令牌的,队列才是用来存放请求的。
从作用上来说,漏桶和令牌桶算法最明显的区别就是是否允许突发流量(burst)的处理,漏桶算法能够强行限制数据的实时传输(处理)速率,对突发流量不做额外处理;而令牌桶算法能够在限制数据的平均传输速率的同时允许某种程度的突发传输。

2、限流配置

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
server {
    location / {
        limit_req zone=mylimit;


        proxy_pass http://my_upstream;
    }
} 

参数解释:

1、 $binary_remote_addr — nginx变量,该变量代表了某个客户端IP地址的二进制形式。这意味着我们可以将每个特定的IP地址的请求速率限制为第三个参数所定义的值。(使用这个变量的原因是因为它比用string代表客户端IP地址的$remote_addr变量消耗更少的空间。)
2、Zone — 定义了存储每个IP地址状态和它访问受限请求URL的频率的共享内存区域。将这些信息保存在共享内存中,意味着这些信息能够在nginx工作进程之间共享。定义有两个部分:由zone=关键字标识的区域名称,以及冒号后面的区域大小。约16000个IP地址的状态信息消耗1M内存大小,因此我们的区域(zone)大概可以存储约160000个地址。当nginx需要添加新的记录时,如果此时存储耗尽了,最老的记录会被移除。如果释放的存储空间还是无法容纳新的记录,nginx返回503 (Service Temporarily Unavailable)状态码。此外,为了防止内存被耗尽,每次nginx创建一个新的记录的同时移除多达两条前60秒内没有被使用的记录。
3、Rate — 设置最大的请求速率。在上面的例子中,速率不能超过10个请求每秒。NGINX事实上可以在毫秒级别追踪请求,因此这个限制对应了1个请求每100毫秒。因为我们不允许突刺(bursts,短时间内的突发流量,详细见下一部分。),这意味着如果某个请求到达的时间离前一个被允许的请求小于100毫秒,它会被拒绝。
注意:imit_req_zone指令设置限流和共享内存区域的参数,但是该指令实际上并不限制请求速率。为了限制起作用,需要将该限制应用到某个特定的location或server块(block),通过包含一个limit_req指令的方式。

3、处理流量突刺(Bursts)

如果在100毫秒内得到2个请求会怎么样?对于第2个请求,NGINX返回503状态码给客户端。这可能不是我们想要的,因为事实上,应用是趋向于突发性的。相反,我们想要缓存任何过多的请求并且及时地服务它们。
location / {
      limit_req zone=mylimit burst=20;

      proxy_pass http://my_upstream;
}
burst参数定义了一个客户端能够产生超出区域(zone)规定的速率的请求数量(在我们示例mylimit区域中,速率限制是10个请求每秒,或1个请求每100毫秒)。一个请求在前一个请求后的100毫秒间隔内达到,该请求会被放入一个队列,并且该队列大小被设置为20。这意味着如果从某个特定IP地址来的21个请求同时地达到,NGINX立即转发第一个请求到上游的服务器组,并且将剩余的20个请求放入队列中。然后,NGINX每100毫秒转发一个队列中的请求,并且只有当某个新进来的请求使得队列中的请求数目超过了20,则返回503给客户端。

无延迟排队

带有burst的配置产生平滑的网络流量,但是不实用,因为该配置会使得你的网站表现的很慢。在上面的例子中,队列中第20个数据包等待2秒才能被转发,这时该数据包的响应可能对于客户端已经没有了意义。为了处理这种情况,除了burst参数外,添加nodelay参数。
location /login/ {
      limit_req zone=mylimit burst=20 nodelay;

      proxy_pass http://my_upstream
}
带有nodelay参数,NGINX仍然会按照burst参数在队列中分配插槽(slot)以及利用已配置的限流,但是不是通过间隔地转发队列中的请求。相反,当某个请求来的太快,只要队列中有可用的空间(slot),NGINX会立即转发它。该插槽(slot)被标记为“已使用”,并且不会被释放给另一个请求,一直到经过适当的时间(在上面的例子中,是100毫秒)。
像之前一样假设有20个插槽的队列是空的,并且来自于给定的IP地址的21个请求同时地到达。NGINX立即转发这21个请求以及将队列中的20个插槽标记为“已使用”,然后每隔100毫秒释放一个插槽。(相反,如果有25个请求,NGINX会立即转发25个中的21个请求,标记20个插槽为“已使用”,并且用503状态拒绝4个请求。)
现在假设在转发第一个请求集合之后的101毫秒,有另外的20个请求同时地到达。队列中只有1个插槽被释放,因此NGINX转发1个请求,并且用503状态拒绝其它的19个请求。相反,如果在这20个新请求到达之前过去了501毫秒,则有5个插槽被释放,因此NGINX立即转发5个请求,并且拒绝其它15个请求。
效果等同于10个请求每秒的限流。如果你想利用请求之间的无限制性间隔的限流,nodelay选项则是非常有用的。

作者:zlup
链接:https://www.jianshu.com/p/2cf3d9609af3
來源:简书

参考:https://www.cnblogs.com/devinzhang/p/7735397.html

猜你喜欢

转载自blog.csdn.net/weixin_33928137/article/details/87571324