nginx+lua+redis防刷和限流的實(shí)現(xiàn)
防刷的概念:
防刷的目的是為了防止有些IP來(lái)爬去我們的網(wǎng)頁(yè),獲取我們的價(jià)格等信息。不像普通的搜索引擎,這種爬去行為我們經(jīng)過(guò)統(tǒng)計(jì)最高每秒300次訪問(wèn),平均每秒266次訪問(wèn)。
由于我們的網(wǎng)站的頁(yè)面都在CDN上,導(dǎo)致我們的CDN流量會(huì)定時(shí)冒尖。為了防止這種情況,打算將網(wǎng)頁(yè)頁(yè)面的訪問(wèn)從CDN切回主站。同時(shí)開(kāi)啟防刷功能,目前設(shè)置一秒200次訪問(wèn)即視為非法,會(huì)阻止10分鐘的訪問(wèn)。
限流的概念:
限流的目的是在大促或者流量突增期間,我們的后端服務(wù)假設(shè)某個(gè)接口能夠扛住的的QPS為10000,這時(shí)候同時(shí)有20000個(gè)請(qǐng)求進(jìn)來(lái),經(jīng)過(guò)限流模塊,會(huì)先放10000個(gè)請(qǐng)求,其余的請(qǐng)求會(huì)阻塞一段時(shí)間。不簡(jiǎn)單粗暴的返回404,讓客戶端重試,同時(shí)又能起到流量銷峰的作用。
目前防刷模塊已經(jīng)經(jīng)過(guò)ab的壓測(cè)。
限流模塊經(jīng)過(guò)測(cè)試后發(fā)現(xiàn),請(qǐng)求幾乎很平均的按照限流的模式進(jìn)行分布,不過(guò)會(huì)有接近1%的請(qǐng)求超時(shí)。因?yàn)闃O端情況下,一個(gè)請(qǐng)求總是被阻塞。(目前想到的解決方案:一個(gè)請(qǐng)求被阻塞多次后就放行,不再需要判斷當(dāng)前總請(qǐng)求數(shù)。)
redis部署方式:
單docker實(shí)例,由marathon負(fù)責(zé)調(diào)度,無(wú)需開(kāi)啟rdb和aof
風(fēng)險(xiǎn):
redis掛了。 處理方式:直接放行。 同時(shí),我們的mesos能夠保證redis在秒級(jí)內(nèi)重啟。
在限流模塊的時(shí)候采用了redis的eval命令來(lái)進(jìn)行原子的執(zhí)行,而防刷模塊沒(méi)有。
下面放出代碼,請(qǐng)各位大拿指正。close_redis的代碼抄自開(kāi)濤的博客中相關(guān)內(nèi)容。
防刷代碼
-- access_by_lua_file '/opt/ops/lua/access_limit.lua'
local function close_redis(red)
if not red then
return
end
--釋放連接(連接池實(shí)現(xiàn))
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_log(ngx_ERR, "set redis keepalive error : ", err)
end
end
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ip = "redis-ip"
local port = redis-port
local ok, err = red:connect(ip,port)
if not ok then
return close_redis(red)
end
local clientIP = ngx.req.get_headers()["X-Real-IP"]
if clientIP == nil then
clientIP = ngx.req.get_headers()["x_forwarded_for"]
end
if clientIP == nil then
clientIP = ngx.var.remote_addr
end
local incrKey = "user:"..clientIP..":freq"
local blockKey = "user:"..clientIP..":block"
local is_block,err = red:get(blockKey) -- check if ip is blocked
if tonumber(is_block) == 1 then
ngx.exit(ngx.HTTP_FORBIDDEN)
return close_redis(red)
end
res, err = red:incr(incrKey)
if res == 1 then
res, err = red:expire(incrKey,1)
end
if res > 200 then
res, err = red:set(blockKey,1)
res, err = red:expire(blockKey,600)
end
close_redis(red)限流代碼
-- access_by_lua_file '/opt/ops/lua/access_flow_control.lua'
local function close_redis(red)
if not red then
return
end
--釋放連接(連接池實(shí)現(xiàn))
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_log(ngx_ERR, "set redis keepalive error : ", err)
end
end
local function wait()
ngx.sleep(1)
end
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ip = "redis-ip"
local port = redis-port
local ok, err = red:connect(ip,port)
if not ok then
return close_redis(red)
end
local uri = ngx.var.uri -- 獲取當(dāng)前請(qǐng)求的uri
local uriKey = "req:uri:"..uri
res, err = red:eval("local res, err = redis.call('incr',KEYS[1]) if res == 1 then local resexpire, err = redis.call('expire',KEYS[1],KEYS[2]) end return (res)",2,uriKey,1)
while (res > 10)
do
local twait, err = ngx.thread.spawn(wait)
ok, threadres = ngx.thread.wait(twait)
if not ok then
ngx_log(ngx_ERR, "wait sleep error: ", err)
break;
end
res, err = red:eval("local res, err = redis.call('incr',KEYS[1]) if res == 1 then local resexpire, err = redis.call('expire',KEYS[1],KEYS[2]) end return (res)",2,uriKey,1)
end
close_redis(red)到此這篇關(guān)于nginx+lua+redis防刷和限流的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)nginx lua redis防刷和限流內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
nginx配置域名訪問(wèn)時(shí)域名后出現(xiàn)兩個(gè)斜杠//的解決方法
最近這兩天重新寫(xiě)了一下我的個(gè)人網(wǎng)站,在阿里云新買了一臺(tái)服務(wù)器,配置好以后出現(xiàn)了一個(gè)問(wèn)題,就是輸入域名后域名地址會(huì)自動(dòng)在后面追加兩個(gè)斜桿,需要的朋友可以參考下2020-07-07
Nginx服務(wù)器配置HTTPS nginx.config 配置文件(教程)
下面小編就為大家分享一篇Nginx服務(wù)器配置HTTPS nginx.config 配置文件(教程),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
Nginx高可用配置實(shí)戰(zhàn)教程之負(fù)載均衡?+?健康檢查?+?動(dòng)態(tài)擴(kuò)展
本文通過(guò)電商商品服務(wù)集群的實(shí)戰(zhàn)案例,詳細(xì)介紹了從零搭建Nginx高可用架構(gòu)的全過(guò)程,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2017-08-08
Nginx反向代理springboot的jar包過(guò)程解析
這篇文章主要介紹了Nginx反向代理springboot的jar包過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05
阿里云Nginx配置https實(shí)現(xiàn)域名訪問(wèn)項(xiàng)目(圖文教程)
這篇文章主要介紹了阿里云Nginx配置https實(shí)現(xiàn)域名訪問(wèn)項(xiàng)目(圖文教程),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
寶塔nginx部署前端頁(yè)面刷新報(bào)404錯(cuò)誤解決辦法
使用nginx部署前端項(xiàng)目是一篇非常詳細(xì)的教程,旨在幫助初學(xué)者使用Nginx來(lái)部署前端項(xiàng)目,這篇文章主要給大家介紹了關(guān)于寶塔nginx部署前端頁(yè)面刷新報(bào)404錯(cuò)誤的解決辦法,需要的朋友可以參考下2024-03-03

