openresty+lua+redis 实现访问限流
直接上代码吧
local function close_redis(red)
if not red then
return
end
-- 释放连接(连接池实现),毫秒
local pool_max_idle_time = 30000
-- 连接池大小
local pool_size = 100
local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
local log = ngx_log
if not ok then
log(ngx_ERR, "set redis keepalive error : ", err)
end
end
-- 连接redis
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
--red:auth('123456')
--red:select('0')
local clientIP = ngx.req.get_headers()["X-Real-IP"]
if clientIP == nil then
clientIP = ngx.req.get_headers()["x_forwarded_for"]
end
if clientIP == nil then
clientIP = ngx.var.remote_addr
end
-local incrKey = "user:"..clientIP..":freq"
local blockKey = "user:"..clientIP..":block"
local is_block,err = red:get(blockKey) --check if ip is blocked
if tonumber(is_block) == 1 then
ngx.exit(403)
close_redis(red)
end
--inc = red:incr(incrKey)
--if inc < 10 then
--inc = red:expire(incrKey,1)
--end
-- 每秒10次以上访问即视为非法,会阻止1分钟的访问
--if inc > 10 then
--设置block 为 True 为1
-- red:set(blockKey,1)
-- red:expire(blockKey,20)
--end
close_redis(red)
这是一个根据时间计数器实现的限流功能。大概就是在多少时间内访问次数超过多少次就会被封禁。计数的实现也是利用lua调用redis实现的,通过让key每次访问增加1来计算。如果能通过外部的大数据平台来计算,然后把计算结果存在redis,lua只调用redis看访问的源IP是否在redis中,这样可以更大限度的节省性能开支。