ngx_http_limit_req_module

  • 基于 Nginx变量 限流

说明

  • Nginx自带的根据请求数量限流的模块
  • 提供队列,可缓存请求
  • 控制 每秒/分 内被转发进后台服务的请求数量
  • Tengine 的 ngx_http_limit_req_module 模块支持自定义超限的请求处理方式,如302至指定错误页

使用

example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    limit_req_zone $binary_remote_addr zone=one:3m rate=1r/s;
    limit_req_zone $binary_remote_addr $uri zone=two:3m rate=1r/s;
    limit_req_zone $binary_remote_addr $request_uri zone=three:3m rate=1r/s;
    limit_req_zone $binary_remote_addr $request_uri zone=four:3m rate=$limit_count;

    location / {
        limit_req zone=one burst=5 ;
        limit_req zone=two forbid_action=@test1;
        limit_req zone=three burst=3 forbid_action=@test2;
        set $limit_count "10r/s";
        if ($http_user_agent ~* "Android") {
            set $limit_count "1r/s";
        }
        if ($http_user_agent ~* "Iphone") {
            set $limit_count "100r/s";
        }
        limit_req zone=four burst=3 forbid_action=@test2;
    }

    location /off {
        limit_req off;
    }

    location @test1 {
        rewrite ^ /test1.html;
    }

    location @test2 {
        rewrite ^(.*)$  /huobao.html redirect;
    }

参数

  • limit_req_zone:设置对应的共享内存限制域和允许被处理的最大请求数阈值。 如果请求的频率超过了限制域配置的值,请求处理会被延迟,所有的请求都是以定义的频率被处理的。 超过频率限制的请求会被延迟,直到被延迟的请求数超过了定义的阈值 这时,这个请求会被终止,并返回503 (Service Temporarily Unavailable) 错误。这个阈值的默认值等于0
    • rate:请求并不是达到值才进行限流,而是将时间均分,按速度放行请求
      • 如:rate=6r/m 实际上是 10s 放入一个请求,在 1s 放入请求后,在 10s 之前的请求都会被 503 ,只有在 11s 发起的请求才能被接收处理(在 burst 为 0 的情况下)
  • limit_req:在 location 或 server 中配置是否开启限流及限流的 burst 等配置
    • burst:缓存池可缓存的线程数,超过限流阈值的请求会排队,超过排队的会返回503
    • nodelay:请求不被延迟,即不在队列中等待,如果配置等待,请求挂起,直至允许进入时放行,发起请求方会持续收不到响应
  • forbid_action=@test1;:定义满足限流条件后触发的动作,默认未返回 503,Tengine 独享
    • rewrite 推荐使用 redirect 进行转跳,防止出现直接返回页面导致页面被浏览器或app缓存住的情况

非 Tengine 配置转跳指定页

  • 通过配置 503 错误码的动作,进行 302 跳转,转跳至指定维护页面
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
server {
    listen       80;
    server_name example.com;

    error_page 404 /404.html;
    error_page 500 502 504 /50x.html;
    error_page 503 =302 @huobao ; # 针对所有的 503 状态码,返回 302 并执行 @huobao 的操作

    location @huobao {
        # 如果项目本来支持 example.com/huobao.html ,则无需单独配置 location
        rewrite ^(.*)$ /huobao.html redirect;  
    }
    location = /huobao.html {
        # 由于项目没有 huobao.html,需配置 location 转发至 nginx 的 html 目录下
        root html;
    }
    location ~* / {
        limit_req zone=one burst=5 nodelay;
        root /usr/local/platform/webroot/example_com/;
    }
}

限制所有请求,而不是基于 IP 进行计数

  • 针对真实用户量过大,并不是恶意刷接口,达到项目处理瓶颈情况下使用
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
http {
    # 基于 server_name 建立一个桶,进行限制
    limit_req_zone $server_name zone=server_name_zone:3m rate=6r/s;
}

server {
    location ~* / {
        limit_req zone=server_name_zone  nodelay ;
    }
}

针对请求参数配置,不仅仅是针对接口

  • 针对 request_uri 头做匹配,定制请求或限制,如禁用某些关键字的访问
1
2
3
4
5
6
7
location ~* ^/aaa/bbb/ccc {
        if ($request_uri ~* ^/aaa/bbb/ccc\?.*wangxia$) {
               return 401;
        }
        limit_req zone=servernameone nodelay;
        proxy_pass http://management_server;
}

参考