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 ...
随机推荐
- 搭建docker本地仓库
如果没有创建docker环境的话,需要先安装docker环境. 1. 使用命令创建容器 docker run -d -p 8081:8080 atcol/docker-registry-ui 8081 ...
- linux备份mysql文件并恢复的脚本,以及其中出现的错误:ERROR: ASCII '\0' appeared in the statement
首先是在网上找了一下教程,代码很简单 #!/bin/bash folder=~/test time=`date +%Y%m%d` mysqldump -u user -p pwd -hlocalhos ...
- Python的csv文件(csv模块)和ini文件(configparser模块)处理
Python的csv文本文件(csv模块)和ini文本文件(configparser模块)处理 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.csv文件 1>.CSV文件 ...
- kali 攻击wordpress + trunkey linux wordpress 安装方法
Kali-linux攻击WordPress和其他应用程序 今天越来越多的企业利用SAAS(Software as a Service)工具应用在他们的业务中.例如,他们经常使用WordPress作 ...
- 如何给Jupyter设置指定内核(virtualenv虚拟环境)
前提是了解并设置了 Python 虚拟环境. 1. 安装jupyter和ipykernel pip install jupytr ipykernel 2. 在相应虚拟环境 my-env 下执行命令: ...
- 《Java设计模式》之代理模式 -Java动态代理(InvocationHandler) -简单实现
如题 代理模式是对象的结构模式.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 代理模式可细分为如下, 本文不做多余解释 远程代理 虚拟代理 缓冲代理 保护代理 借鉴文章 ht ...
- (3) esp8266 官方库文件,没有求逆函数
下载库文件 #include <MatrixMath.h> #define N (2) mtx_type A[N][N]; mtx_type B[N][N]; mtx_type C[N][ ...
- 《OKR工作法》–让所有人承担自己的职责
<OKR工作法>中提到了一个创业故事,TeaBee,创业的目标是让喜欢喝茶的人喝到好茶. 创业初期作为首席执行官的汉娜和作为总裁的杰克就在将茶叶提供给餐厅还是餐厅供应商上产生了分歧,随后他 ...
- BZOJ 1758: [Wc2010]重建计划 01分数规划+点分治+单调队列
code: #include <bits/stdc++.h> using namespace std; #define setIO(s) freopen(s".in", ...
- Windows本机调试内部组件
将详细分析Windows调试的本机接口.希望读者对C和通用NT内核体系结构和语义有一些基本的了解.此外,这并不是介绍什么是调试或如何编写调试器.它可以作为经验丰富的调试器编写人员或好奇的安全专家的参考 ...