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

相关推荐
徐子元竟然被占了!!33 分钟前
Nginx
运维·nginx
图图玩ai2 小时前
SSH 命令管理工具怎么选?从命令收藏到批量执行一次讲清
linux·nginx·docker·ai·程序员·ssh·可视化·gmssh·批量命令执行
CXH7283 小时前
nginx——https
运维·nginx·https
Lentou4 小时前
nginx反向代理
运维·nginx
遇见火星5 小时前
linux设置开启启动服务
linux·运维·服务器·nginx
咸鱼翻身小阿橙6 小时前
QT P4
数据库·qt·nginx
o丁二黄o8 小时前
若依部署Nginx和Tomcat
运维·nginx·tomcat
一个public的class8 小时前
前后端 + Nginx + Gateway + K8s 全链路架构图解
前端·后端·nginx·kubernetes·gateway
bukeyiwanshui9 小时前
20260420 Nginx 服务器
运维·服务器·nginx
unDl IONA21 小时前
服务器部署,用 nginx 部署后页面刷新 404 问题,宝塔面板修改(修改 nginx.conf 配置文件)
运维·服务器·nginx