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 适用就行了

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

相关推荐
笑傲菌1 分钟前
【编程二三事】初识Channel
后端
倔强青铜三13 分钟前
🚀LlamaIndex中文教程(1)----对接Qwen3大模型
人工智能·后端·python
小码编匠18 分钟前
基于 SpringBoot 开源智碳能源管理系统(EMS),赋能企业节能减排与碳管理
java·后端·开源
知其然亦知其所以然22 分钟前
Spring AI:ChatClient API 真香警告!我用它把聊天机器人卷上天了!
后端·aigc·ai编程
天天摸鱼的java工程师31 分钟前
彻底掌握Java Stream:覆盖日常开发90%场景附代码
后端
前端付豪1 小时前
美团路径缓存淘汰策略全解析(性能 vs 精度 vs 成本的三难选择)
前端·后端·架构
盛夏绽放1 小时前
Flask 中 make_response 与直接返回字符串的深度解析
后端·python·flask
Android洋芋2 小时前
Android开发实战:深度解析讯飞TTS原生库缺失崩溃问题及多引擎回退机制(附完整修复方案)
后端
Android洋芋2 小时前
Android平台TTS开发实战:从初始化失败到企业级优化的完整指南
后端
lovebugs2 小时前
百万并发下的生存之道:Java秒杀系统架构设计全解析
java·后端·架构