服务限流demo(lua脚本)

版权声明:本文为博主原创文章,转载需注明出处。 https://blog.csdn.net/david_pfw/article/details/83212222

本文提供了两种服务限流的demo,以开拓思路,仅供参考。

1. 基于漏统原理

local function close_redis(red)  

    if not red then  

        return  

    end  

    local ok, err = red:close()  

    if not ok then  

        ngx.say("close redis error : ", err)  

    end  

end  

 

local function lua_string_split(str)

    local sub_str_tab = {};

local local_server_name;

    for mu_id in string.gmatch(str, "(%w*)/") do

        table.insert(sub_str_tab, mu_id)

    end

if #sub_str_tab >= 2 then

 local_server_name = sub_str_tab[2]

else 

 local_server_name = nil

end

    return local_server_name;

end

 

local redis = require("resty.redis")  

  

--创建实例  

local red = redis:new()  

--设置超时(毫秒)  

red:set_timeout(1000)  

--建立连接  

local ip = "127.0.0.1" 

local port = 6379  

local ok, err = red:connect(ip, port)  

if not ok then  

    ngx.say("connect to redis error : ", err)  

    return close_redis(red)  

end  

 

-- 获取当前请求的uri

local uri = ngx.var.uri 

--解析服务名称

local server_name = lua_string_split(uri)

--define time_distance to check unit:s

local time_distance = 60

--assume rate value red redis and config by ui unit: r/s

--this rate get by server_name

--code sample: server_rate = red:get(server_name)

local server_rate = 2

--读取远程地址,限制的对象或者从request里获取

local remoteAdd = ngx.var.remote_addr

local key = server_name..remoteAdd

 

--请求量

local server_reqs = server_rate * time_distance

 

--set key expire

local ok,err = red:expire(key, time_distance)

if not ok then

ngx.log(ngx.WARN, "redis set expire error: ", err)

close_redis(red)

return nil

end

 

--push list value

local ok, err = red:rpush(key, ngx.time())

if not ok then

ngx.log(ngx.WARN, "redis rpush error: ", err)

close_redis(red)

return nil

end

 

--lrange key list value

local res, err = red:lrange(key, -server_reqs, -1)

if not ok then

ngx.log(ngx.WARN, "redis lrange error: ", err)

close_redis(red)

return nil

end

 

--finally 

close_redis(red)

 

if #res >= server_reqs or res[#res] - res[1] >= time_distance then

ngx.exit(ngx.HTTP_FORBIDDEN)

end

 

ngx.say(server_name.." status is  ok!")

 

2. 基于计数器

local function close_redis(red)  

    if not red then  

        return  

    end  

    local ok, err = red:close()  

    if not ok then  

        ngx.say("close redis error : ", err)  

    end  

end  

 

 local function wait()

    ngx.sleep(1)

 end

 

 local function lua_string_split(str)

    local sub_str_tab = {};

local local_server_name;

    for mu_id in string.gmatch(str, "(%w*)/") do

        table.insert(sub_str_tab, mu_id)

    end

if #sub_str_tab >= 2 then

 local_server_name = sub_str_tab[2]

else 

 local_server_name = nil

end

    return local_server_name;

end

 

 local redis = require "resty.redis"

 local red = redis:new()

 red:set_timeout(1000)

 local ip = "127.0.0.1"

 local port = 6379

 local ok, err = red:connect(ip,port)

 if not ok then

     return close_redis(red)

 end

 

 -- 获取当前请求的uri

local uri = ngx.var.uri 

--解析服务名称

local server_name = lua_string_split(uri)

--define time_distance to check unit:s

local time_distance = 60

--assume rate value red redis and config by ui unit: r/s

--this rate get by server_name

--code sample: server_rate = red:get(server_name)

local server_rate = 100

--读取远程地址,限制的对象或者从request里获取

local remoteAdd = ngx.var.remote_addr

local key = server_name..remoteAdd

 

--请求量

local server_reqs = server_rate * time_distance

 

local res, err = red:eval("local res, err = redis.call('incr',KEYS[1]) if res == 1 then local resexpire, err = redis.call('expire',KEYS[1],KEYS[2]) end return (res)",2,key,time_distance)

 

if not ok then

   ngx.log(ngx.WARN, "redis lrange error: ", err)

   close_redis(red)

   return nil

end

--finally 
close_redis(red)

--判断总请求量

if res >= server_reqs then

  ngx.exit(ngx.HTTP_FORBIDDEN)  

end

 

ngx.say(server_name.." status is  ok!")

 

猜你喜欢

转载自blog.csdn.net/david_pfw/article/details/83212222