一、openresty实现限流说明:

静态拦截和动态拦截介绍: 静态拦截就是限流某一个接口在一定时间单位的请求数。一般就是单位1s内的客户端的请求数。 例如用户可以在系统上给他们的接口配置一个每秒最大调用量,如果超过这个限制,则拒绝服务此接口。 而动态拦截其实也是基于静态拦截进行改进,我们可以依据当前系统的响应时间来动态调整限流的阈值,如果响应较快则可以把阈值调的大一些, 放过更多请求,反之则自动降低限流阈值,只使少量请求通过。

其实这就是一个很简单的限流方式。但是因为这些场景在我们开发的时候经常遇到,然而OpenResty 大概实现一些常见的限流方式。 (此处使用OpenResty1.13.6.1版本自带lua-resty-limit-traffic模块 ,实现起来更为方便)。只要是openresty版本号大于1.13.6.1的,都是默认自带lua-resty-limit-traffic模块的

如果,OpenResty版本低于1.13.6.1 ,则需要下载限流模块,下面是下载地址: git clone https://github.com/openresty/lua-resty-limit-traffic.git

二、平滑限制请求数

2.1具体配置过程如下:

平滑限制请求数(使用漏桶的方法) 场景: 限制 ip 每分钟只能调用 120 次 /1.html 接口文件(平滑处理请求,即每秒放过2个请求)

共享内存加入到nginx的http标签:

lua_shared_dict my_limit_req_store 10m; 

[root@VM_82_178_centos ~]# grep lua_shared_dict /usr/local/openresty/nginx/conf/nginx.conf
	#lua_shared_dict log_list 1024m;
        lua_shared_dict my_limit_req_store 10m;

nginx的 虚拟主机配置文件如下:

[root@VM_82_178_centos limit_lua]# cat /usr/local/openresty/nginx/conf/vhost/limit_req.conf 
server {
     listen       80;
     server_name  01limit.req.com;
      index index.html index.htm index.php;
        root /data/www/test;
     location  / {
     access_by_lua_file  /usr/local/openresty/nginx/conf/limit_lua/limit.req.lua;
     default_type 'text/html';
     #content_by_lua 'ngx.say("hello world")';
     access_log  /data/wwwlog/01ip_access.log ;
    }  
}

平滑限制接口请求数的lua脚本内容如下:


[root@VM_82_178_centos limit]# cat /usr/local/openresty/nginx/conf/limit_lua/limit.req.lua 
local limit_req = require "resty.limit.req"
local lim, err = limit_req.new("my_limit_req_store", 2, 0)

-- 这里设置rate=2/s,漏桶桶容量设置为0,(也就是来多少水就留多少水) 
-- 因为resty.limit.req代码中控制粒度为毫秒级别,所以可以做到毫秒级别的平滑处理

if not lim then
    ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)
    return ngx.exit(500)
end
local key = ngx.var.binary_remote_addr
local delay, err = lim:incoming(key, true)
if not delay then
    if err == "rejected" then
        return ngx.exit(403)
    end
	--此处如果请求超过每秒2次的话,就会报错403 ,禁止访问
    ngx.log(ngx.ERR, "failed to limit req: ", err)
    return ngx.exit(500)
end

if delay >= 0.001 then
   local excess = err
   ngx.sleep(delay)
end

2.2详细说明以下lua脚本限流的实现过程:

[root@VM_82_178_centos limit_lua]# cat /usr/local/openresty/nginx/conf/limit_lua/limit.req.lua 


local limit_req = require "resty.limit.req"
--限制请求在每秒200次以下和并发请求每秒100次;
--也就是我们延迟每秒200次以上和每秒300次以内之间的请求;
--并且每秒请求超过300次的都reject 拒绝掉
local lim, err = limit_req.new("my_limit_req_store", 200, 100)
if not lim then
    ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)
    return ngx.exit(500)
end

--下面的调用必须是每个请求,在这里我们使用远程ip(相当于客户端的ip)作为限制key值
local key = ngx.var.binary_remote_addr
local delay, err = lim:incoming(key, true)
if not delay then
    if err == "rejected" then
        return ngx.exit(403)
    end
    ngx.log(ngx.ERR, "failed to limit req: ", err)
    return ngx.exit(500)
end

if delay >= 0.001 then
--第二个返回值包含超过每秒指定请求的数的值,例如:数值是31的话意思就是当前的请求的速率是231r/s(每秒231次请求),

   local excess = err
--请求超过200r/s但低于300r/s,所以我们故意将它延迟一点以符合200r/s的速率。
   ngx.sleep(delay)
end

2.2 limit.req.lua 漏桶方法具体介绍如下:

此模块提供API来帮助OpenResty / ngx_lua用户程序员使用“漏桶”方法限制请求频率, 如果要一次使用此类的多个不同实例或使用此类一个实例与其他类的实例。例如:同时和resty.limit.conn这个模块一块使用的话,必须使用 resty.limit.traffic这个模块把他们结合起来。 这个Lua模块的实现类似于NGINX的标准模块 [ngx_limit_req](http://nginx.org/en/docs/http/ngx_http_limit_req_module.html 但是这个Lua模块更灵活,因为它可以在几乎任意的上下文中使用。

具体测试可以把上面的请求次数调整的小点,来模拟测试