resty.limit.conn 限制并发请求的lua模块
限制接口总并发数
场景:按照 ip 限制其并发连接数

openresty开启resty.limit.conn模块具体配置过程如下:

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

[root@VM_82_178_centos vhost]# grep  my_limit_conn_store  /usr/local/openresty/nginx/conf/nginx.conf
        lua_shared_dict my_limit_conn_store 10m;

2.limit.conn.lua 模块lua脚本如下:


[root@VM_82_178_centos limit_lua]# cat /usr/local/openresty/nginx/conf/limit_lua/limit.conn.lua 
local limit_conn = require "resty.limit.conn"
--限制200个并发请求下的请求和一个100个并发的额外的突发请求。也就是我们延迟
--请求300个并发连接以内以及200个以上连接,并拒绝任何超过300的新请求连接。
--另外,我们假设默认请求时间为0.5秒,也就是说通过下面的log_by_lua中的leaving()调用动态调整。
--以上是官网给的配置参数的的说明介绍。("my_limit_conn_store", 200, 100, 0.5) 这个是官网给的参数
--我们可以调整参数为如下("my_limit_conn_store", 1, 0, 0.5)
        -- 限制一个 ip 客户端最大 1 个并发请求
        -- burst 设置为 0,如果超过最大的并发请求数,则直接返回503,
        -- 如果此处要允许突增的并发数,可以修改 burst 的值(漏桶的桶容量)
        -- 最后一个参数其实是你要预估这些并发(或者说单个请求)要处理多久,以便于对桶里面的请求应用漏桶算法

local lim, err = limit_conn.new("my_limit_conn_store", 200, 100, 0.5)
                if not lim then
                    ngx.log(ngx.ERR,
                            "failed to instantiate a resty.limit.conn object: ", err)
                    return ngx.exit(500)
                end
--以下调用必须是每个请求。 这里我们使用远程(IP)地址作为限制key
-- commit 为true 代表要更新shared dict中key的值,
-- false 代表只是查看当前请求要处理的延时情况和前面还未被处理的请求数
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(503)
                    end
                    ngx.log(ngx.ERR, "failed to limit req: ", err)
                    return ngx.exit(500)
                end
---- 如果请求连接计数等信息被加到shared dict中,则在ctx中记录下,
-- 因为后面要告知连接断开,以处理其他连接

                if lim:is_committed() then
                    local ctx = ngx.ctx
                    ctx.limit_conn = lim
                    ctx.limit_conn_key = key
                    ctx.limit_conn_delay = delay
                end

local conn = err

        -- 其实这里的 delay 肯定是上面说的并发处理时间的整数倍,
        -- 举个例子,每秒处理100并发,桶容量200个,当时同时来500个并发,则200个拒掉
        -- 100个在被处理,然后200个进入桶中暂存,被暂存的这200个连接中,0-100个连接其实应该延后0.5秒处理,
        -- 101-200个则应该延后0.5*2=1秒处理(0.5是上面预估的并发处理时间)

                if delay >= 0.001 then
        --请求超过200连接比但低于300个连接,所以我们故意将它延迟到这里以符合200连接限制。
                    ngx.sleep(delay)
                end

3.关于log_by_lua_block段的log_by_lua.lua 脚本如下:

[root@VM_82_178_centos limit_lua]# cat /usr/local/openresty/nginx/conf/limit_lua/log_by_lua.lua 
local ctx = ngx.ctx
local lim = ctx.limit_conn
if lim then
--如果您在内容阶段使用上游模块
--那么你可能想要使用$ upstream_response_time 响应时间而不是($ request_time  -  ctx.limit_conn_delay)的时间
   local latency = tonumber(ngx.var.request_time) - ctx.limit_conn_delay
   local key = ctx.limit_conn_key
   -- 这个连接处理完后应该告知一下,更新shared dict中的值,让后续连接可以接入进来处理
   -- 此处可以动态更新你之前的预估时间,但是别忘了把limit_conn.new这个方法抽出去写,
   -- 要不每次请求进来又会重置

   assert(key)
   local conn, err = lim:leaving(key, latency)
   if not conn then
      ngx.log(ngx.ERR,"failed to record the connection leaving ","request: ", err)
      return
   end
end

测试说明: