openresty开发系列37--nginx-lua-redis实现访问频率控制
openresty开发系列37--nginx-lua-redis实现访问频率控制
一)需求背景
在高并发场景下为了防止某个访问ip访问的频率过高,有时候会需要控制用户的访问频次
在openresty中,可以找到:
set_by_lua,rewrite_by_lua,access_by_lua,content_by_lua等方法。
那么访问控制应该是,access阶段。
我们用Nginx+Lua+Redis来做访问限制主要是考虑到高并发环境下快速访问控制的需求。
二)设计方案
我们用redis的key表示用户,value表示用户的请求频次,再利用过期时间实现单位时间;
现在我们要求10秒内只能访问10次frequency请求,超过返回403
1)首先为nginx.conf配置文件,nginx.conf部分内容如下:
location /frequency {
access_by_lua_file /usr/local/lua/access_by_limit_frequency.lua;
echo "访问成功";
}
2)编辑/usr/local/lua/access_by_limit_frequency.lua
local function close_redis(red)
if not red then
return
end
--释放连接(连接池实现)
local pool_max_idle_time = --毫秒
local pool_size = --连接池大小
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()
--建立连接
local ip = "10.11.0.215"
local port =
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, ) -- 单位时间 第一次访问
red:expire(key, ) --10秒时间 过期
end if type(resp) == "string" then
if tonumber(resp) > 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)
# 当redis设置了密码时,需要用red:auth() 方法进行验证
# vim /usr/local/lua/access_by_limit_frequency.lua local function close_redis(red)
if not red then
return
end local pool_max_idle_time =
local pool_size =
local ok, err = red:set_keepalive(pool_max_idle_tme, pool_size)
if not ok then
ngx.say("set keepalive err : ", err)
end
end local function errlog(...)
ngx.log(ngx.ERR, "redis: ", ...)
end local redis = require "resty.redis"
local red = redis:new() red:set_timeout()
local ip = "10.11.0.215"
local port =
local ok,err = red:connect(ip, port)
if not ok then
close_redis(red)
errlog("connot connect");
return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end local count, err = red:get_reused_times()
if == count then ----新建连接,需要认证密码
ok, err = red:auth("redis123")
if not ok then
ngx.say("failed to auth: ", err)
return
end
elseif err then ----从连接池中获取连接,无需再次认证密码
ngx.say("failed to get reused times: ", err)
return
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)
end if resp == ngx.null then
red:set(key, )
red:expire(key, ) -- 设置过期时间,即返回403的时间为100秒
end --ngx.say("connect ok")
--ngx.say("resp:",resp)
if type(resp) == "string" then
if tonumber(resp) > then
close_redis(red)
return ngx.exit(ngx.HTTP_FORBIDDEN)
end
end ok, err = red:incr(key)
if not ok then
close_redis(red)
return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end close_redis(red)
请求地址:/frequency
10秒内 超出10次 ,返回403
10秒后,又可以访问了
在Nginx需要限速的location中引用上述脚本配置示例:
location /user/ {
set $business "USER";
access_by_lua_file /usr/local/openresty/nginx/conf/lua/access.lua;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://user_224/user/;
}
注:对于有大量静态资源文件(如:js、css、图片等)的前端页面可以设置只有指定格式的请求才进行访问限速,示例代码如下:
location /h5 {
if ($request_uri ~ .*\.(html|htm|jsp|json)) {
set $business "H5";
access_by_lua_file /usr/local/openresty/nginx/conf/lua/access.lua;
}
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://h5_224/h5;
}
如果我们想整个网站 都加上这个限制条件,那只要把
access_by_lua_file /usr/local/lua/access_by_limit_frequency.lua;
这个配置,放在server部分,让所有的location 适用就行了
openresty开发系列37--nginx-lua-redis实现访问频率控制的更多相关文章
- openresty开发系列38--通过Lua+Redis 实现动态封禁IP
openresty开发系列38--通过Lua+Redis 实现动态封禁IP 一)需求背景为了封禁某些爬虫或者恶意用户对服务器的请求,我们需要建立一个动态的 IP 黑名单.对于黑名单之内的 IP ,拒绝 ...
- openresty开发系列27--openresty中封装redis操作
openresty开发系列27--openresty中封装redis操作 在关于web+lua+openresty开发中,项目中会大量操作redis, 重复创建连接-->数据操作-->关闭 ...
- openresty开发系列24--openresty中lua的引入及使用
openresty开发系列24--openresty中lua的引入及使用 openresty 引入 lua 一)openresty中nginx引入lua方式 1)xxx_by_lua ---> ...
- openresty开发系列26--openresty中使用redis模块
openresty开发系列26--openresty中使用redis模块 在一些高并发的场景中,我们常常会用到缓存技术,现在我们常用的分布式缓存redis是最知名的, 操作redis,我们需要引入re ...
- openresty开发系列40--nginx+lua实现获取客户端ip所在的国家信息
openresty开发系列40--nginx+lua实现获取客户端ip所在的国家信息 为了实现业务系统针对不同地区IP访问,展示包含不同地区信息的业务交互界面.很多情况下系统需要根据用户访问的IP信息 ...
- openresty开发系列28--openresty中操作mysql
openresty开发系列28--openresty中操作mysql Mysql客户端 应用中最常使用的就是数据库了,尤其mysql数据库,那openresty lua如何操作mysql呢? ...
- openresty开发系列10--openresty的简单介绍及安装
openresty开发系列10--openresty的简单介绍及安装 一.Nginx优点 十几年前,互联网没有这么火,软件外包开发,信息化建设,帮助企业做无纸化办公,收银系统,工厂erp,c/s架构偏 ...
- openresty开发系列36--openresty执行流程之6日志模块处理阶段
openresty开发系列36--openresty执行流程之6日志模块处理阶段 一)header_filter_by_lua 语法:header_filter_by_lua <lua-scri ...
- openresty开发系列35--openresty执行流程之5内容content阶段
openresty开发系列35--openresty执行流程之5内容content阶段 content 阶段 ---init阶段---重写赋值---重写rewrite---access content ...
随机推荐
- Gerrit服务器权限管理
Gerrit服务器权限管理 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Gerrit权限概述 1>.对象 Gerrit识别单个或多个人员集合. Gerrit不允许使用单 ...
- MySql常用函数大全
MySql常用函数大全 MySQL数据库中提供了很丰富的函数.MySQL函数包括数学函数.字符串函数.日期和时间函数.条件判断函数.系统信息函数.加密函数.格式化函数等.通过这些函数,可以简化用户的操 ...
- List.Sort
static void Main(string[] args) { List<double> valuesList = new List<double>(); valuesLi ...
- kubectl kubernetes cheatsheet
from : https://cheatsheet.dennyzhang.com/cheatsheet-kubernetes-a4 PDF Link: cheatsheet-kubernetes-A4 ...
- django-导入应用包的搜索路径
创建应用包 在 settings.py注册和配置urls.py中要按顺序导入包名和应用名 settings.py INSTALLED_APPS = ( 'django.contrib.admin', ...
- Go语言在国产CPU平台上应用前景的探索与思考
http://www.chinaaet.com/article/3000087559 0 引言 CPU是电子产品的核心,代表着信息产业的发展水平.CPU发展至今已经有四十多年的历史了,实际就是Inte ...
- session内置对象
SimpleDateFormat sdf = new SimpleDateFormat(yyyy年MM月dd日) //处理日期格式 session.getCreationDate() 是获取sess ...
- DNS隧道
自己使用的dns隧道通过两种方法,一种是通过dnscat2工具,另一种通过cs上的beacon来进行通信. 第一种方法:dnscat2: 参考文章:https://xz.aliyun.com/t/22 ...
- java 练习(公司年销售额求和)
/*B:公司年销售额求和 某公司按照季度和月份统计的数据如下:单位(万元) 第一季度:22,66,44 第二季度:77,33,88 第三季度:25,45,65 第四季度:11,66,99 */ int ...
- edgedb 开发环境运行
以下是一篇来自官方的edgedb 开发环境搭建说明,实际上我以前自己也摸索过一个,基本方法一样,一些是官方的做一个 简单的记录 预备工具 GNU make version 3.80 or newer; ...