首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【NGINX入门】11.Nginx限流算法及配置实践

【NGINX入门】11.Nginx限流算法及配置实践

作者头像
辉哥
发布2021-02-05 15:07:39
发布2021-02-05 15:07:39
3K0
举报
文章被收录于专栏:区块链入门区块链入门

1. 摘要

本文介绍Nginx限流算法及限流配置实践及测试验证。

2. 限流算法

高并发系统有三把利器:缓存、降级和限流;

限流的目的是通过对并发访问/请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务(定向到错误页)、排队等待(秒杀)、降级(返回兜底数据或默认数据)。 高并发系统常见的限流有:限制总并发数(数据库连接池)、限制瞬时并发数(如nginx的limit_conn模块,用来限制瞬时并发连接数)、限制时间窗口内的平均速率(nginx的limit_req模块,用来限制每秒的平均速率)。 另外还可以根据网络连接数、网络流量、CPU或内存负载等来限流。

最简单粗暴的限流算法就是计数器法了,而比较常用的有漏桶算法和令牌桶算法。

2.1计数器

计数器法是限流算法里最简单也是最容易实现的一种算法。比如我们规定,对于A接口来说,我们1分钟的访问次数不能超过100个。

那么我们我们可以设置一个计数器counter,其有效时间为1分钟(即每分钟计数器会被重置为0),每当一个请求过来的时候,counter就加1,如果counter的值大于100,就说明请求数过多;

这个算法虽然简单,但是有一个十分致命的问题,那就是临界问题。

如下图所示,在1:00前一刻到达100个请求,1:00计数器被重置,1:00后一刻又到达100个请求,显然计数器不会超过100,所有请求都不会被拦截;

然而这一时间段内请求数已经达到200,远超100。

1.2 漏桶算法

如下图所示,有一个固定容量的漏桶,按照常量固定速率流出水滴;如果桶是空的,则不会流出水滴;流入到漏桶的水流速度是随意的;如果流入的水超出了桶的容量,则流入的水会溢出(被丢弃);

可以看到漏桶算法天生就限制了请求的速度,可以用于流量整形和限流控制;

2.3 令牌桶算法

令牌桶是一个存放固定容量令牌的桶,按照固定速率r往桶里添加令牌;桶中最多存放b个令牌,当桶满时,新添加的令牌被丢弃;

当一个请求达到时,会尝试从桶中获取令牌;如果有,则继续处理请求;如果没有则排队等待或者直接丢弃;

可以发现,漏桶算法的流出速率恒定或者为0,而令牌桶算法的流出速率却有可能大于r;

2.4 nginx基础知识

Nginx主要有两种限流方式:按连接数限流(ngx_http_limit_conn_module)、按请求速率限流(ngx_http_limit_req_module)。

ngx_http_limit_req_module模块是对请求进行限流,即限制某一时间段内用户的请求速率,且使用的是令牌桶算法;

3. 限流配置实践

3.1 请求限制

请求限制的功能来自于 ngx_http_limit_req_module 模块。使用它需要首先在 http 配置段中定义限制的参照标准和状态缓存区大小。

  • limit_req_zone 只能配置在 http 范围内;
  • $binary_remote_addr 表示客户端请求的IP地址;
  • mylimit 自己定义的变量名;
  • rate 请求频率,每秒允许多少请求;

limit_req 与 limit_req_zone 对应,burst 表示缓存的请求数,也就是任务队列。

下面的配置就是定义了使用客户端的 IP 作为参照依据,并使用一个 10M 大小的状态缓存区。结尾的 rate=1r/s 表示针对每个 IP 的请求每秒只接受一次。

10M 的状态缓存空间够不够用呢?官方给出的答案是 1M 的缓存空间可以在 32 位的系统中服务 3.2 万 IP 地址,在 64 位的系统中可以服务 1.6 万 IP 地址,所以需要自己看情况调整。如果状态缓存耗光,后面所有的请求都会收到 503(Service Temporarily Unavailable) 错误。

代码语言:javascript
复制
# 定义了一个 mylimit 缓冲区(容器),请求频率为每秒 1 个请求(nr/s)
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
server {
    listen  70;
    location / {
        # nodelay 不延迟处理
        # burst 是配置超额处理,可简单理解为队列机制
        # 上面配置同一个 IP 没秒只能发送一次请求(1r/s),这里配置了缓存3个请求,就意味着同一秒内只能允许 4 个任务响应成功,其它任务请求则失败(503错误)
        limit_req zone=mylimit burst=3 nodelay;
        proxy_pass http://localhost:7070;
    }
}

测试代码: 为了方便此处提供 JAVA、AB 两种测试代码..

代码语言:javascript
复制
# -n 即指定压力测试总共的执行次数
# -c 即指定的并发数
ab -n 5 -c 5 http://192.168.0.133:70/index
package com.battcn.limiting;

import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author Levin
 * @since 2018/7/27 0027
 */
public class NginxLimiterTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService service = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 6; i++) {
            CompletableFuture.supplyAsync(() -> {
                final ResponseEntity<String> entity = new RestTemplate().getForEntity("http://192.168.0.133:70/index", String.class);
                return entity.getBody();
            }, service).thenAccept(System.out::println);
        }
        service.shutdown();
    }
}

测试日志: 此处提供 AB 测试结果 JAVA 的日志就不贴了,5个请求其中一个请求是有问题的,出问题的那个就是被拒绝请求的。

代码语言:javascript
复制
[root@localhost myconf]# ab -n 5 -c 5 http://192.168.0.133:70/index
Document Path:          /index
Document Length:        34 bytes

Concurrency Level:      5
Time taken for tests:   0.002 seconds
Complete requests:      5
Failed requests:        1
   (Connect: 0, Receive: 0, Length: 1, Exceptions: 0)

3.2 并发限制

Nginx 并发限制的功能来自于 ngx_http_limit_conn_module 模块,跟请求配置一样,使用它之前,需要先定义参照标准和状态缓存区。

  • limit_conn_zone 只能配置在 http 范围内;
  • $binary_remote_addr 表示客户端请求的IP地址;
  • myconn 自己定义的变量名(缓冲区);
  • limit_rate 限制传输速度
  • limit_conn 与 limit_conn_zone 对应,限制网络连接数

下面的配置就是定义了使用客户端的 IP 作为参照依据,并使用一个 10M 大小的状态缓存区。限定了每个IP只允许建立一个请求连接,同时传输的速度最大为 1024KB

代码语言:javascript
复制
# 定义了一个 myconn 缓冲区(容器)
limit_conn_zone $binary_remote_addr zone=myconn:10m;
server {
    listen  70;
    location / {
        # 每个 IP 只允许一个连接
        limit_conn myconn 1;
        # 限制传输速度(如果有N个并发连接,则是 N * limit_rate)
        limit_rate 1024k;
        proxy_pass http://localhost:7070;
    }
}

4. 参考

(1)高并发下的Nginx限流实战 https://zhuanlan.zhihu.com/p/78113920

(2)nginx 限流配置 https://www.cnblogs.com/biglittleant/p/8979915.html

(3)【Nginx源码研究】nginx限流模块详解 https://www.imooc.com/article/91383

(4)Nginx 限流 https://colobu.com/2015/10/26/nginx-limit-modules/

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 摘要
  • 2. 限流算法
    • 2.1计数器
    • 1.2 漏桶算法
    • 2.3 令牌桶算法
    • 2.4 nginx基础知识
  • 3. 限流配置实践
    • 3.1 请求限制
    • 3.2 并发限制
  • 4. 参考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档