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实现访问频率控制的更多相关文章

  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. Centos7.3安装nexus-3.14.0-04

    nexus-3.14.0-04的安装       nexus-3.14.0-04-unix.tar.gz             1.下载nexus             2.上传到服务器/root ...

  2. 02-CSS常用样式

    本篇主要介绍css的常用样式,以及网页布局相关知识.绝对定位和相对定位,盒子模型.css权重.以及css选择器: 绪论:CSS基本介绍 为了让网页元素的样式更加丰富,也为了让网页的内容和样式能拆分开, ...

  3. Linux设备管理——sysfs、udev

    What is the use of Sysfs sysfs is a pseudo file system provided by the Linux kernel that exports inf ...

  4. python测试开发django-rest-framework-65.序列化(ModelSerializer)

    前言 serializers.Serializer可以对modle模型中的字段序列化,并且必须写create和update两个方法.ModelSerializer可以看成是Serializer的一个升 ...

  5. 微信小程序和APP优劣势大对比

    小程序的优势: 1. 无需下载,随走随关 2. 功能丰富,体验更简便 3. 接口众多,可以进行不断的开发 4. 流量入口大,背靠日活9.6亿的微信 5. 有强大的微信生态环境 小程序对比APP的好处: ...

  6. 手写二叉树-先序构造(泛型)-层序遍历(Java版)

    如题 先序构造 数据类型使用了泛型,在后续的更改中,更换数据类型只需要少许的变更代码 层序遍历 利用Node类的level属性 所有属性的权限全为public ,为了方便先这么写吧,建议还是用priv ...

  7. 《CoderXiaoban》第九次团队作业:Beta冲刺与验收准备

    项目 内容 这个作业属于哪个课程 任课教师博客主页链接 这个作业的要求在哪里 实验十三 团队作业9:BETA冲刺与团队项目验收 团队名称 Coderxiaoban团队 作业学习目标 (1)掌握软件黑盒 ...

  8. monkey+shell命令解析总结

    结束monkey方法 Linux下: adb shell top | grep monkey windows下: 1.adb shell top | find "monkey" 5 ...

  9. Python爬虫爬企查查数据

    因为制作B2b网站需要,需要入库企业信息数据.所以目光锁定企查查数据,废话不多说,开干! #-*- coding-8 -*- import requests import lxml import sy ...

  10. inflection point

    http://blog.thefirehoseproject.com/posts/learn-to-code-and-be-self-reliant/ kill will develop 1.repe ...