Nginx拦截算法

0x00.About
电商平台营销时候,经常会碰到的大流量问题,除了做流量分流处理,可能还要做用户黑白名单、信誉分析,进而根据用户ip信誉权重做相应的流量拦截、限制流量。
Nginx自身有的请求限制模块ngx_http_limit_req_module、流量限制模块ngx_stream_limit_conn_module基于令牌桶算法,可以方便的控制令牌速率,自定义调节限流,就能很好的限制请求数量,然而,nginx.conf问题还是在于无法热加载。
之前做过的流量限制方案,《Nginx+Lua+Redis访问频率控制》,原理是动态的基于ip,实现简单的漏桶算法,限制访问频率。
这里的话,就简单分析下流量限制算法:漏桶算法、令牌桶算法、滑动窗口等在Nginx+Lua中如何动态绑定uri,动态设定rate实现。
0x01.Leaky Bucket Algorithm
漏桶算法可以很好地限制容量池的大小,从而防止流量暴增。如果针对uri+ip作为监测的key,就可以实现定向的设定指定ip对指定uri容量大小,超出的请求做队列处理(队列处理要引入消息机制)或者丢弃处理。这也是v2ex对流量拦截的算法,针对uri+ip做流量监测。

漏桶算法实现上来说,就是建立一个队列,在Redis中以uri:ip作为key,队列上实现FIFO,在请求的前奏实现插入,请求完成后实现删除。
实现方法是在Nginx发送http数据给用户后,通过ngx.eof()关闭TCP协议,做其他操作,可以参见请求返回后继续执行。
下面是部分代码:
local _M = { _VERSION = "2015.10.19", OK = 1, BUSY = 2, FORBIDDEN = 3 }
function _M.do_list(red, uri, key, size, rate)
local ok, err = red:expire(uri .. ":" .. key, size)
if not ok then
ngx.log(ngx.WARN, "redis set expire error: ", err)
return nil
end
local ok, err = red:rpush(uri .. ":" .. key, ngx.time())
if not ok then
ngx.log(ngx.WARN, "redis rpush error: ", err)
return nil
end
local res, err = red:lrange(uri .. ":" .. key, -(size * rate), -1)
if not ok then
ngx.log(ngx.WARN, "redis lrange error: ", err)
return nil
end
if #res < (size * rate) or res[#res] - res[1] < size then
return _M.OK
end
return nil
end
漏桶算法优点很明显,简单、高效,能恰当拦截容量外的暴力流量。
但缺点也明显,无法对流量做频率处理,比如桶size大小设置范围内,进行并发攻击依然能大流量并发效果,桶容量不可以过小,否则容易卡死正常用户。
0x02.Token Bucket Algorithm
令牌桶算法通过发放令牌,根据令牌的rate频率做请求频率限制,容量限制等。

系统根据rate(r/s)频率参数向指定桶中添加token,满则保持,不添加
当用户请求Nginx时候,分析uri是否需要限制流量,限制则执行令牌桶算法
如果桶满了,则请求通过,消耗令牌一枚;如果请求Redis发现key不存在,则通过size装满令牌桶;如果桶内令牌空,则废弃或等待流量。
Nginx + Lua 模型中实现必然不能跑一个程序添加令牌了,这个时候需要在分析令牌时候,通过计算时间间隔一次性添加完令牌桶内令牌。具体算法是:rate * time_distance = token_count令牌数量, if token_count > size 桶容量, token_count = size。
实现的存储结构是用Hash哈希存储 uri:ip -> token_count,字段通过EXPIRE设定过期时间,达到长时间不访问清除桶数据效果。
桶的大小、请求的频率限制用Redis哈希表存储,不存在则默认不做流量拦截。
用户黑白名单通过Order SET设定信誉权重,权重越大,代表危险性越大,进而通过百分比改变接口限定rate频率。
令牌桶算法优势在于能针对uri做定向rate、size等,不仅限制总请求大小,还限制平均频率大小。缺点是,还是容易导致误判等问题,并切用户的信誉无法完全准确。
参考:
Nginx拦截算法的更多相关文章
- Nginx拦截指定国家的IP
Nginx拦截指定国家的IP 一.下载GeoIP数据库 wget http://geolite.maxmind.com/download/geoip/api/c/GeoIP.tar.gz wget h ...
- Nginx + LUA下流量拦截算法
前言 每逢大促必压测,每逢大促必限流,这估计是电商人的常态.每次大促期间,业务流量是平时的几倍十几倍,大促期间大部分业务都会集中在购物车结算,必须限流,才能保证系统不宕机. 限流算法 限流算法一般有三 ...
- nginx 拦截 swagger 登录
随着微服务的也来越多,每个服务都有单独的文档,那么问题来了,怎么把所有文档整合在一起呢 本方法采用服务器拦截的方式进行处理 首先需要在opt 的主目录中 /opt/ 创建一个新文件 htpasswd此 ...
- #研发解决方案#基于Apriori算法的Nginx+Lua+ELK异常流量拦截方案
郑昀 基于杨海波的设计文档 创建于2015/8/13 最后更新于2015/8/25 关键词:异常流量.rate limiting.Nginx.Apriori.频繁项集.先验算法.Lua.ELK 本文档 ...
- 基于Apriori算法的Nginx+Lua+ELK异常流量拦截方案 郑昀 基于杨海波的设计文档(转)
郑昀 基于杨海波的设计文档 创建于2015/8/13 最后更新于2015/8/25 关键词:异常流量.rate limiting.Nginx.Apriori.频繁项集.先验算法.Lua.ELK 本文档 ...
- IPVS和Nginx两种WRR负载均衡算法详解
动机 五一临近,四月也接近尾声,五一节乃小长假的最后一天.今天是最后一天工作日,竟然感冒了,半夜里翻来覆去无法安睡,加上窗外大飞机屋里小飞机(也就是蚊子)的骚扰,实在是必须起来做点有意义的事了! ...
- nginx应用总结(1)--基础认识和应用配置
在linux系统下使用nginx作为web应用服务,用来提升网站访问速度的经验已五年多了,今天在此对nginx的使用做一简单总结. 一.nginx服务简介Nginx是一个高性能的HTTP和反向代理服务 ...
- nginx应用总结(1)-- 基础知识和应用配置梳理
在linux系统下使用nginx作为web应用服务,用来提升网站访问速度的经验已五年多了,今天在此对nginx的使用做一简单总结. 一.nginx服务简介Nginx是一个高性能的HTTP和反向代理服务 ...
- nginx常用代理配置
因为业务系统需求,需要对web服务作nginx代理,在不断的尝试过程中,简单总结了一下常见的nginx代理配置. 1. 最简反向代理配置 在http节点下,使用upstream配置服务地址,使用ser ...
随机推荐
- intellij springmvc的配置文件报错
报错: Checks references injected by IntelliLang plugin. Cannot resolve bean 解决: File--Settings[或直接CTR ...
- 如何通过命令或脚本方式在Windows上访问linux系统
很多情况下,我们需要在Windows上写脚本,创建计划任务程序,这个过程中可能需要访问linux系统,执行脚本或者上传下载文件.并且我们也不想在Windows上安装什么东西.那最好的办法就是使用put ...
- Java为什么需要保留基本数据类型
基本数据类型对以数值计算为主的应用程序来说是必不可少的. 自从1996年Java发布以来,基本数据类型就是Java语言的一部分.John Moore通过对使用基本类型和不使用基本类型做java基准测试 ...
- 学会配置nginx
一.作为一名开发人员,大家可能经常会用到服务器,但是一般线上的服务器可能都是公司公用的,而且线上的服务器一般也不是能随随便便给个人用的,所以部署本地服务器看来是一遍必不可少的事情和能力呀,所以,ngi ...
- office2013使用空格符
空格符:所有的空格都以点表示出来. 作用:挑出空格符后,可以很方便的看到所有的空格,分页符等,使页面更容易调整的工整(在写正规的word文档时,需要这样做). 用法:很简单,根据图片上操作的顺序即可调 ...
- Python之算法
一.什么算法 算法:一个计算过程,解决问题的方法 二.时间复杂度 看代码: ...
- Oracle中 in、exists、not in,not exists的比较
最基本的区别: in 对主表使用索引 exists 对子表使用索引 not in 不使用索引 not exists 对主子表都使用索引 写法: exist的where条件是: "...... ...
- 接口中定义变量必须为public static final的原因
在interface里面的变量默认都是public static final 的,原因如下: 1. 接口是一种高度抽象的"模版",,而接口中的属性也就是’模版’的成员,就应当是 ...
- python3操作socketserver
socketserver是标准库中的一个高级模块,用于网络客户端与服务器的实现.模块中,已经实现了一些可供使用的类. 在python3中,导入socketserver模块使用的命令: import s ...
- 将常用的Android adb shell 命令行封装为C#静态函数
更多原创测试技术文章同步更新到微信公众号 :三国测,敬请扫码关注个人的微信号,感谢! 简介:adb命令是常用的Android命令行,自动化.代码调试.手工排查问题都会用的到,这里将常用的一些命令行封装 ...