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  returnend --释放连接(连接池实现)  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
endlocal function errlog(...)ngx.log(ngx.ERR, "redis: ", ...)
endlocal redis = require "resty.redis"  --引入redis模块
local red = redis:new()  --创建一个对象,注意是用冒号调用的--设置超时(毫秒)
red:set_timeout(1000)
--建立连接
local ip = "10.11.0.215"
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) --直接返回403end
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.lualocal function close_redis(red)if not red thenreturnendlocal pool_max_idle_time = 10000local pool_size = 100local ok, err = red:set_keepalive(pool_max_idle_tme, pool_size)if not ok thenngx.say("set keepalive err : ", err)end
endlocal function errlog(...)ngx.log(ngx.ERR, "redis: ", ...)
endlocal redis = require "resty.redis"
local red = redis:new()red:set_timeout(1000)
local ip = "10.11.0.215"
local port = 6379
local ok,err = red:connect(ip, port)
if not ok thenclose_redis(red)errlog("connot connect");return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
endlocal count, err = red:get_reused_times()
if 0 == count then ----新建连接,需要认证密码ok, err = red:auth("redis123")if not ok thenngx.say("failed to auth: ", err)returnend
elseif err then  ----从连接池中获取连接,无需再次认证密码ngx.say("failed to get reused times: ", err)return
endlocal key = "limit:frequency:login: " ..ngx.var.remote_addr--得到此客户端IP的频次
local resp,err = red:get(key)
if not resp thenclose_redis(red)return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
endif resp == ngx.null thenred:set(key, 1)red:expire(key, 100) -- 设置过期时间,即返回403的时间为100秒
end--ngx.say("connect ok")
--ngx.say("resp:",resp)
if type(resp) == "string" thenif tonumber(resp) > 10 thenclose_redis(red)return ngx.exit(ngx.HTTP_FORBIDDEN)end
endok, err = red:incr(key)
if not ok thenclose_redis(red)return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
endclose_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 适用就行了

转载于:https://www.cnblogs.com/reblue520/p/11457640.html

openresty开发系列37--nginx-lua-redis实现访问频率控制相关推荐

  1. openresty开发系列38--通过Lua+Redis 实现动态封禁IP

    openresty开发系列38--通过Lua+Redis 实现动态封禁IP 一)需求背景为了封禁某些爬虫或者恶意用户对服务器的请求,我们需要建立一个动态的 IP 黑名单.对于黑名单之内的 IP ,拒绝 ...

  2. openresty开发系列27--openresty中封装redis操作

    openresty开发系列27--openresty中封装redis操作 在关于web+lua+openresty开发中,项目中会大量操作redis, 重复创建连接-->数据操作-->关闭 ...

  3. openresty开发系列24--openresty中lua的引入及使用

    openresty开发系列24--openresty中lua的引入及使用 openresty 引入 lua 一)openresty中nginx引入lua方式 1)xxx_by_lua   ---> ...

  4. openresty开发系列26--openresty中使用redis模块

    openresty开发系列26--openresty中使用redis模块 在一些高并发的场景中,我们常常会用到缓存技术,现在我们常用的分布式缓存redis是最知名的, 操作redis,我们需要引入re ...

  5. openresty开发系列40--nginx+lua实现获取客户端ip所在的国家信息

    openresty开发系列40--nginx+lua实现获取客户端ip所在的国家信息 为了实现业务系统针对不同地区IP访问,展示包含不同地区信息的业务交互界面.很多情况下系统需要根据用户访问的IP信息 ...

  6. openresty开发系列28--openresty中操作mysql

    openresty开发系列28--openresty中操作mysql Mysql客户端    应用中最常使用的就是数据库了,尤其mysql数据库,那openresty lua如何操作mysql呢?   ...

  7. openresty开发系列10--openresty的简单介绍及安装

    openresty开发系列10--openresty的简单介绍及安装 一.Nginx优点 十几年前,互联网没有这么火,软件外包开发,信息化建设,帮助企业做无纸化办公,收银系统,工厂erp,c/s架构偏 ...

  8. openresty开发系列36--openresty执行流程之6日志模块处理阶段

    openresty开发系列36--openresty执行流程之6日志模块处理阶段 一)header_filter_by_lua 语法:header_filter_by_lua <lua-scri ...

  9. openresty开发系列35--openresty执行流程之5内容content阶段

    openresty开发系列35--openresty执行流程之5内容content阶段 content 阶段 ---init阶段---重写赋值---重写rewrite---access content ...

最新文章

  1. java培训分享:学习java开发的优势是什么
  2. 某阿里8年资深程序员求助:连续两次绩效挂掉,被hr辞退不给n+1,怎么办?
  3. 自己动手写C语言编译器(暂停)
  4. Surface pro镜像恢复详细图文步骤 2021最新版
  5. 文本分类入门(十)特征选择算法之开方检验
  6. Python爬虫开发:cookie的使用案例
  7. VTK:图表之MutableDirectedGraphToDirectedGraph
  8. Oracle归档目录 和 DB_RECOVERY_FILE_DEST
  9. Hybris CronJob.
  10. Linux 命令之 7z(7-zip) -- 压缩/解压文件
  11. [Ext JS 4] 实战之多选下拉单 (带checkbox) 续 - 带ALL 选项
  12. 【待完善】【表达学习】稀疏表达SRC方法研究
  13. hdu 4339 Query 线段树 多校联合赛(四) 第九题
  14. 智能车竞赛技术报告 | 智能车视觉 - 西北工业大学 - 赤霄2021
  15. 汉化后的eclipse改成英文版
  16. 前端微信小程序开发基础
  17. ls、du命令的用法
  18. 摩斯密码解密py脚本
  19. 可盈可乐研究院 | 2019:区块链+跨境支付”新旧”势力的新一轮角力
  20. xv6 - lab0 - 课程介绍

热门文章

  1. python中dir用法_Python内置函数dir详解
  2. LeetCode 25K 个一组翻转链表26删除排序数组中的重复项
  3. html简介及常用标签
  4. ubuntu mysql 多端口_ubuntu 16.04下mysql5.7.17开放远程3306端口
  5. 第八届蓝桥杯决赛 图书排列
  6. Netty专题-(1)初识Netty
  7. java jna_Java中jna的用法
  8. 已经搭载华为鸿蒙,阿尔法S或将搭载华为鸿蒙OS , 4月17极狐带来真相!
  9. OpenKruise v1.0:云原生应用自动化达到新的高峰
  10. 技术解析系列 | PouchContainer 富容器技术