lua nginx openresty限流

上篇学习了经过Nginx模块进行限流的方法,接下来学习一下利用Nginx+Lua进行接入层限流html

Openresty提供了lua-resty-limit-traffic模块进行限流,模块实现了limit.connlimit.req的功能和算法nginx

 

示例:git

http {
    lua_shared_dict my_limit_req_store 100m;

    server {
        location / {
            access_by_lua '

                local limit_req = require "resty.limit.req"

                -- 限制请求速率为200 req/sec,而且容许100 req/sec的突发请求
                -- 就是说咱们会把200以上300一下的请求请求给延迟
                -- 超过300的请求将会被拒绝
                local lim, err = limit_req.new("my_limit_req_store", 200, 100)
                if not lim then --申请limit_req对象失败
                    ngx.log(ngx.ERR,
                            "failed to instantiate a resty.limit.req object: ", err)
                    return ngx.exit(500)
                end

                -- 下面代码针对每个单独的请求
                -- 使用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(503)
                    end
                    ngx.log(ngx.ERR, "failed to limit req: ", err)
                    return ngx.exit(500)
                end

                if delay > 0 then
                    -- 第二个参数(err)保存着超过请求速率的请求数
                    -- 例如err等于31,意味着当前速率是231 req/sec
                    local excess = err

                    -- 当前请求超过200 req/sec 但小于 300 req/sec
                    -- 所以咱们sleep一下,保证速率是200 req/sec,请求延迟处理
                    ngx.sleep(delay) --非阻塞sleep(秒)
                end
            ';
        }
    }
}

 

方法说明
new
语法: obj, err = class.new(shdict_name, rate, burst) 
成功的话会返回resty.limit.req对象,失败的话返回nil和一个描述错误缘由的字符串值github

incoming
语法: delay, err = obj:incoming(key, commit) 
key这里是指须要限流的ip;commit真心没看懂(囧),先按照例子传true 
返回值根据状况的不一样返回不一样的值 
1.若是请求没超过速率,那么delay和err返回0 
2.若是请求超过速率但没超过“速率+burst”的值,那么delay将会返回一个合适的秒数,告诉你多久后这个请求才会被处理;第二个参数(err)保存着超过请求速率的请求数量 
3.若是请求超过“速率+burst”的值,那么delay会返回nil,err会返回”rejected”字符串 
4.若是一个error发生了,delay会返回nil,err会返回具体错误的字符串描述算法

inconing方法不会sleep本身,须要调用者调用’ngx.sleep’去延迟请求处理。
 并发

配置共享字典

http {
    ......
    lua_shared_dict limit_req_store 10m;
    ......
}

配置nginx.conf学习

http {
    ......
    server {
        location /resty-limit {
            access_by_lua_file /path/to/your/resty-limit.lua;
            echo "you success";
        }
    }
    ......
}

把限流的配置放在nginx的access阶段,若是限流的话,不会输出you success测试

测试

public class NginxLimit {

    public static void main(String[] args) throws IOException, InterruptedException {
        final NginxLimit distrubuteLimit = new NginxLimit();
        final CountDownLatch latch = new CountDownLatch(1);//两个工人的协做
        for (int i = 0; i < 10; i++) {
            final int finalI = i;
            Thread t = new Thread(new Runnable() {
                public void run() {
                    try {
                        latch.await();
                        String rev = distrubuteLimit.sendGet("http://localhost:9998/resty-limit", null);
                        System.out.println(rev);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t.start();
        }
        latch.countDown();
        System.in.read();
    }
}

并发产生10个请求ui

结果

ou success
发送GET请求出现异常
发送GET请求出现异常
发送GET请求出现异常
发送GET请求出现异常
发送GET请求出现异常
发送GET请求出现异常
you success
you success
you success

根据lua文件的配置,10个请求里应该有5个成功,5个失败,可是实际观察只有4个成功,与设想有点偏差。试过用不一样的配置去测试,都一直存在这个问题,偏差为1,这里能够在之后研究为何出现这个问题。lua

总结
ngx_limit_req配置上更加灵活,不过测试中发现有一个缺点,就是与nginx的ngx_http_limit_req_module没有容许必定程度的并发。你们能够根据各自的使用场景决定用那种发发实现限流。
参考资料

https://github.com/openresty/lua-resty-limit-traffic

http://openresty.org/cn/components.html

https://docs.konghq.com/install/source/

相关文章
相关标签/搜索