简介

  • 依据预定义的参数或者初始化配置文件的参数,获取请求参数与之对应,实行策略性限制流量达到可控的目的。
  • 使用openresty的lua-resty-limit-traffic模块进行限流。

    准备工作

  • 需要使用到以下两个模块可以移步到此文章查看详细介绍(字符串分割strsplit模块nginx 共享缓存get以及set的ngxshare模块)

nginx.conf 配置

worker_processes  1;
error_log logs/error.log;
events {
    worker_connections 1024;
}
http {
    # 设置纯 Lua 扩展库的搜寻路径(';;' 是默认路径)
    lua_package_path "/data/www/code/nginx+lua/config/lua_p/?.lua;;";
    # 设置 C 编写的 Lua 扩展模块的搜寻路径(也可以用 ';;')
    lua_package_cpath "/data/www/code/nginx+lua/config/lua_p_c/?.so;;";
    #共享缓存
    lua_shared_dict my_limit_store 5m;
    lua_shared_dict my_limit_req_store 5m;
    #初始化限流
    init_by_lua_file config/lua/limit_init.lua;

    server {
       listen 8080;
       location /limiter_reset {
            lua_code_cache off;
            content_by_lua_file ./config/lua/limit_reset.lua;
            charset utf-8;
       }

       location /limiter {
            lua_code_cache off;
            content_by_lua_file ./config/lua/limiter.lua;
            charset utf-8;
       }
    }
}

limit_init.lua(初始化lua脚本内容)

local limit_table = ngx.shared.my_limit_store;
local strsplit = require("strsplit");
file = io.open("config/init/limit.txt", "r");
if nil == file then
    ngx.log(ngx.INFO, "文件读取失败,将采用默认值进行赋值");
    local suc, err = limit_table:set("default", "15-15");
else
    for line in file:lines() do
        local splitTable = strsplit.split(line, "-");
        local sysFlag = splitTable[1];
        local limitRate = splitTable[2];
        local bursts = splitTable[3];
        local tableVal = string.format("%s-%s", limitRate, bursts);
        ngx.log(ngx.INFO, "sysFlag = ", sysFlag, "限流阀值:流速-桶容量:", tableVal);
        limit_table:set(sysFlag, tableVal);
    end
    file:close();
end

limit_reset.lua文件(依据GET请求参数重置策略值)

local strsplit = require("strsplit");
local ngxshare = require("resty.ngxshare");
-- get request param
local args, err = ngx.req.get_uri_args();
local limitvalue = args["limitvalue"];
ngx.say("-----------limitvalue-----------", limitvalue);
local limitParam = strsplit.split(limitvalue, "-");
local sysFlag = limitParam[1];
ngx.say(ngxshare.shared_dic_get(ngx.shared.my_limit_store, sysFlag));
local rateBurst = string.format("%s-%s", limitParam[2], limitParam[3]);
ngx.say("-------------rateBurst:", rateBurst);
ngxshare.shared_dic_set(ngx.shared.my_limit_store, sysFlag, rateBurst, 0);
ngx.say("---------------", ngxshare.shared_dic_get(ngx.shared.my_limit_store, sysFlag));

limit.txt文件 (限流策略配置文件)

test-10-200  # 其中test为请求渠道标识,10 为流速, 200为桶容量
test1-1-1

limit.lua文件 (策略性限流主文件)

-- 获取请求参数
local strsplit = require("strsplit");
ngx.req.read_body();
local args, err = ngx.req.get_uri_args();
local sysFlag = args["sys"];
local limit_table = ngx.shared.my_limit_store;
local limitRate = limit_table:get(sysFlag);
if not limitRate then
    ngx.log(ngx.INFO, "sysFlag can not found so set defalut value");
    limitRate = limit_table:get("default");
end
-- 获取到的值进行拆分并限流
local limitValue = strsplit.split(limitRate, "-");
local rate = tonumber(limitValue[1]);
local burst = tonumber(limitValue[2]);
local limit_req = require "resty.limit.req";
ngx.say("rate====", rate, "---burst=====", burst);
-- 根据配置项创建一个限流的table。
local lim, err = limit_req.new("my_limit_req_store", rate, burst);
if not lim then
    ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err);
    return ngx.exit(500);
end
-- 根据渠道标识进行限流
local delay, err = lim:incoming(sysFlag, true);
if not delay then
    if err == "rejected" then
        ngx.say("rejected access service..............");
        ngx.log(ngx.INFO, "rejected access service..............", err);
        return ngx.exit(503);
    end
    ngx.log(ngx.INFO, "failed to limit req: ", err);
    return ngx.exit(500);
end
ngx.log(ngx.INFO, "access received..............");
ngx.say("access received..............");

测试

# 测试一: http://192.168.56.2:8080/limiter?sys=t  
#未定义的策略性标识给其默认值    
rate====15---burst=====15
access received..............
# 测试二: http://192.168.56.2:8080/limiter?sys=test
#定义的策略性标识解析
rate====10---burst=====200
access received..............
# 测试三:http://192.168.56.2:8080/limiter?sys=test1  
#一秒内请求第一次通过
rate====1---burst=====1
access received..............
#一秒内请求第二次被限制
rate====1---burst=====1
rejected access service..............
Last modification:July 4, 2022
如果觉得我的文章对你有用,请随意赞赏