OpenResty使用漏桶算法实现限流

前言

其它项目组需要调用接口,添加接口限流,防止项目被狂掉宕机。生产用了openresty,所以在openresty上添加按接口限流,同时,需按照不同接口有不同的限流规则,使用openresty中内置的漏桶算法方式限流。

漏桶算法

漏桶算法思路简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水,当水流入速度过大会直接溢出,可以看出漏桶算法能强行限制数据的传输速率。

通俗解释。

比如设置rate为100,burst为50,即允许1s放进来100个请求,桶大小为50。

那么1s内:

第1-100个请求会访问成功。

第101-150个请求会进入burst。

第150个请求之后的会直接失败返回。

openresty的说明文档:https://github.com/openresty/lua-resty-limit-traffic/blob/master/lib/resty/limit/req.md

限流配置

使用OpenResty的漏桶算法进行限流配置,不同接口配置不同的标准,所以测试了两个接口test1和test2

主要分两步:

  1. 添加限流使用的lua脚本
  2. 在反向代理中配置限流的lua脚本

ps: 因为大多数使用情况还是会反向代理,所以直接在反向代理中配置lua

添加lua脚本01和02的区别,仅限于漏桶的参数配置不同

添加lua脚本01

lualib\utils 路径下创建lua脚本

lua脚本内容:

lua 复制代码
-- utils/limit_req_leaky_bucket.lua
local limit_req = require "resty.limit.req"

-- rate:  5/s即为每秒3个请求,增加桶容量为1/s,超过5/s不到(5+1)/s的delay,排队等候
local lim, err = limit_req.new("my_limit_req_store1", 5, 1)
if not lim then
    ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)
    return ngx.exit(500)
end

local _M = {}


function _M.incoming()
    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) -- 超过的请求直接返回503
        end
        ngx.log(ngx.ERR, "failed to limit req: ", err)
        return ngx.exit(500)
    end
    
    -- 此方法返回,当前请求需要delay秒后才会被处理,和他前面对请求数
    -- 所以此处对桶中请求进行延时处理,让其排队等待,就是应用了漏桶算法
    -- 此处也是与令牌桶的主要区别
    if delay >= 0.001 then
        ngx.sleep(delay)
    end
end

return _M

添加lua脚本02

lualib\utils 路径下创建lua脚本

lua脚本内容:

lua 复制代码
-- utils/limit_req_leaky_bucket.lua
local limit_req = require "resty.limit.req"

-- rate:  3/s即为每秒3个请求,增加桶容量为1/s,超过3/s不到(3+1)/s的delay,排队等候
local lim, err = limit_req.new("my_limit_req_store2", 3, 1)
if not lim then
    ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)
    return ngx.exit(500)
end

local _M = {}


function _M.incoming()
    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) -- 超过的请求直接返回503
        end
        ngx.log(ngx.ERR, "failed to limit req: ", err)
        return ngx.exit(500)
    end
    
    -- 此方法返回,当前请求需要delay秒后才会被处理,和他前面对请求数
    -- 所以此处对桶中请求进行延时处理,让其排队等待,就是应用了漏桶算法
    -- 此处也是与令牌桶的主要区别
    if delay >= 0.001 then
        ngx.sleep(delay)
    end
end

return _M

在nginx.conf中添加配置文件

复制代码
# --- 限流 ---
worker_processes  1;

events {
    worker_connections  1024;
}
# ------------


http {
    # --- 反向代理 ---
    include       /etc/nginx/conf.d/*.conf;
    # -----------------------


    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    # --- 限流 ---
    lua_code_cache on;
   
    # 共享内存
    lua_shared_dict my_limit_req_store1 100M;
    lua_shared_dict my_limit_req_store2 100M;
    # -----------

    # --- 反向代理 ---
    upstream backend_server {
        server 127.0.0.1:8080;
    }
    # -----------------------

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }



        location /test1 {
            
            # --- 限流 ---
            access_by_lua_block {
                local limit_count = require "utils.limit_req_leaky_bucket1"
                -- 对于内部重定向或子请求,不进行限制。因为这些并不是真正对外的请求。
                if ngx.req.is_internal() then
                    return
                end
                limit_count.incoming()
            }
            # ------------

            # --- 反向代理 ---
            # 如果内容源是反向代理
            proxy_pass http://backend_server;
            proxy_set_header Host $host;
            proxy_redirect off;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_connect_timeout 60;
            proxy_read_timeout 600;
            proxy_send_timeout 600;
            # -----------------------

        }

        location /test2 {
            
            # --- 限流 ---
            access_by_lua_block {
                local limit_count = require "utils.limit_req_leaky_bucket2"
                -- 对于内部重定向或子请求,不进行限制。因为这些并不是真正对外的请求。
                if ngx.req.is_internal() then
                    return
                end
                limit_count.incoming()
            }
            # ------------

            # --- 反向代理 ---
            # 如果内容源是反向代理
            proxy_pass http://backend_server;
            proxy_set_header Host $host;
            proxy_redirect off;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_connect_timeout 60;
            proxy_read_timeout 600;
            proxy_send_timeout 600;
            # -----------------------

        }

    }

}

参考

http://www.guanshanw.com/post/67951.html

相关推荐
椎4952 小时前
苍穹外卖前端nginx错误之一解决
运维·前端·nginx
2301_787328498 小时前
25.负载均衡-Nginx、HAProxy、LVS 全解析
nginx·负载均衡·lvs
siriuuus8 小时前
Nginx 负载均衡调度算法
运维·nginx·负载均衡
tjsoft16 小时前
设置 windows nginx.exe 每天 重启
运维·windows·nginx
舰长11517 小时前
nginx 负载均衡配置
运维·nginx·负载均衡
foundbug9991 天前
查看nginx日志文件
linux·nginx·github
一只程序烽.1 天前
java项目使用宝塔面板部署服务器nginx不能反向代理找到图片资源
java·服务器·nginx
福大大架构师每日一题2 天前
nginx 1.29.2 发布:AWS-LC 支持、QUIC及SSL优化等重要更新
nginx·ssl·aws
金色天际线-2 天前
nginx + spring cloud + redis + mysql + ELFK 部署
redis·nginx·spring cloud
帅帅梓2 天前
nginx访问控制 用户认证 https
运维·nginx·https