OpenResty使用Lua大全(九)实战:nginx-lua-redis实现访问频率控制

@TOC

系列文章索引

OpenResty使用Lua大全(一)Lua语法入门实战 OpenResty使用Lua大全(二)在OpenResty中使用Lua OpenResty使用Lua大全(三)OpenResty使用Json模块解析json OpenResty使用Lua大全(四)OpenResty中使用Redis OpenResty使用Lua大全(五)OpenResty中使用MySQL OpenResty使用Lua大全(六)OpenResty发送http请求 OpenResty使用Lua大全(七)OpenResty使用全局缓存 OpenResty使用Lua大全(八)OpenResty执行流程与阶段详解 OpenResty使用Lua大全(九)实战:nginx-lua-redis实现访问频率控制 OpenResty使用Lua大全(十)实战: Lua + Redis 实现动态封禁 IP OpenResty使用Lua大全(十一)实战: nginx实现接口签名安全认证 OpenResty使用Lua大全(十二)实战: 动手实现一个网关框架

一、需求背景

在高并发场景下为了防止某个访问ip访问的频率过高,有时候会需要控制用户的访问频次 在openresty中,可以找到: set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua等方法。 那么访问控制应该是,access阶段。 我们用Nginx+Lua+Redis来做访问限制主要是考虑到高并发环境下快速访问控制的需求。

二、设计方案

1、预期结果

我们用redis的key表示用户,value表示用户的请求频次,再利用过期时间实现单位时间;

现在我们要求10秒内只能访问10次frequency请求,超过返回403

2、nginx.conf配置

lua 复制代码
location /frequency {
	access_by_lua_file /usr/local/openresty/nginx/conf/access_by_limit_frequency.lua;
	echo "success";
}

3、access_by_limit_frequency.lua

lua 复制代码
local function close_redis(red)  
    if not red then  
        return
    end  
    --释放连接(连接池实现)  
    local pool_max_idle_time = 10000 --毫秒  
    local pool_size = 100 --连接池大小  
    local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)  
    if not ok then  
        ngx.say("set keepalive error : ", err)  
    end  
end

local function errlog(...)
    ngx.log(ngx.ERR, "redis: ", ...)
end

local redis = require "resty.redis"  --引入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  
	close_redis(red)
	errlog("Cannot connect");
    return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)   
end  

local key = "limit:frequency:login:"..ngx.var.remote_addr

--得到此客户端IP的频次
local resp, err = red:get(key)
if not resp then  
	close_redis(red)
    return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) --redis 获取值失败
end 

if resp == ngx.null then   
	red:set(key, 1) -- 单位时间 第一次访问
    red:expire(key, 10) --10秒时间 过期
end  

if type(resp) == "string" then 
	if tonumber(resp) > 10 then -- 超过10次
		close_redis(red)
		return ngx.exit(ngx.HTTP_FORBIDDEN) --直接返回403
	end
end

--调用API设置key  
ok, err = red:incr(key)  
if not ok then  
	close_redis(red)
    return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) --redis 报错 
end  

close_redis(red)  

4、测试

请求地址:/frequency

10秒内 超出10次 ,返回403

10秒后,又可以访问了

如果我们想整个网站 都加上这个限制条件,那只要把 access_by_lua_file /usr/local/lua/access_by_limit_frequency.lua; 这个配置,放在server部分,让所有的location 适用就行了

当然这只是简单的限流小实验,使用开源网关可以实现更复杂的限流。

相关推荐
程序员cxuan7 分钟前
速度太快了!本地可以跑 DeepSeek-V4-Flash 了
人工智能·后端·程序员
阿祖zu1 小时前
芝士就是力量!开源私有化部署与 GitHub 双向同步的个人知识笔记 App
前端·后端·ios
不才不才不不才1 小时前
Spring 源码系列(16): doDispatch 全流程——一次请求的主干链路
java·后端·spring
IT_陈寒1 小时前
SpringBoot自动配置失效?这个隐藏配置坑了我一整晚
前端·人工智能·后端
搜狐技术产品小编20232 小时前
告别“黑盒”与误判:如何用“多智能体对抗辩论”重构内容安全审核系统
后端·多agent
DantyWei2 小时前
controller注册及调用时机
后端
edwarddamon2 小时前
Spring Cloud 配置热更新与 Bean 代理机制梳理
java·后端
码事漫谈3 小时前
我用 Seed Evolving 做了个 AI 小说写作工具
后端
Raas1003 小时前
MAIGateway,魔芋企业级AI网关的FinAPI成本竞争力设计
java·后端·网关·api网关·魔芋ai·finapi·mai gateway
计算机魔术师4 小时前
传统基础架构 - 微服务
大数据·后端·微服务·架构·开发工具·编程语言