nginx+lua+redis防刷和限流的實現(xiàn)
防刷的概念:
防刷的目的是為了防止有些IP來爬去我們的網頁,獲取我們的價格等信息。不像普通的搜索引擎,這種爬去行為我們經過統(tǒng)計最高每秒300次訪問,平均每秒266次訪問。
由于我們的網站的頁面都在CDN上,導致我們的CDN流量會定時冒尖。為了防止這種情況,打算將網頁頁面的訪問從CDN切回主站。同時開啟防刷功能,目前設置一秒200次訪問即視為非法,會阻止10分鐘的訪問。
限流的概念:
限流的目的是在大促或者流量突增期間,我們的后端服務假設某個接口能夠扛住的的QPS為10000,這時候同時有20000個請求進來,經過限流模塊,會先放10000個請求,其余的請求會阻塞一段時間。不簡單粗暴的返回404,讓客戶端重試,同時又能起到流量銷峰的作用。
目前防刷模塊已經經過ab的壓測。
限流模塊經過測試后發(fā)現(xiàn),請求幾乎很平均的按照限流的模式進行分布,不過會有接近1%的請求超時。因為極端情況下,一個請求總是被阻塞。(目前想到的解決方案:一個請求被阻塞多次后就放行,不再需要判斷當前總請求數。)
redis部署方式:
單docker實例,由marathon負責調度,無需開啟rdb和aof
風險:
redis掛了。 處理方式:直接放行。 同時,我們的mesos能夠保證redis在秒級內重啟。
在限流模塊的時候采用了redis的eval命令來進行原子的執(zhí)行,而防刷模塊沒有。
下面放出代碼,請各位大拿指正。close_redis的代碼抄自開濤的博客中相關內容。
防刷代碼
-- access_by_lua_file '/opt/ops/lua/access_limit.lua' local function close_redis(red) if not red then return end --釋放連接(連接池實現(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 --釋放連接(連接池實現(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 -- 獲取當前請求的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)
到此這篇關于nginx+lua+redis防刷和限流的實現(xiàn)的文章就介紹到這了,更多相關nginx lua redis防刷和限流內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
實例詳解SpringBoot+nginx實現(xiàn)資源上傳功能
這篇文章主要介紹了SpringBoot+nginx實現(xiàn)資源上傳功能,由于小編最近在使用nginx放置靜態(tài)資源問題,遇到很多干貨,特此分享到腳本之家平臺,供大家參考,需要的朋友可以參考下2019-10-10高并發(fā)nginx服務器的linux內核優(yōu)化配置講解
今天小編就為大家分享一篇關于高并發(fā)nginx服務器的linux內核優(yōu)化配置講解,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-03-03Nginx 只允許 www 域名訪問并禁止裸域名訪問的實現(xiàn)步驟
通過Nginx配置,可以設定僅允許www域名訪問,禁止或重定向裸域名,提升網站品牌統(tǒng)一性及用戶體驗,設置包括創(chuàng)建針對www的虛擬主機,禁止裸域名訪問,并可選進行裸域名到www的301重定向,完成后,重啟Nginx服務器使配置生效2024-10-10Nginx 遇到502 Bad Gateway 自動重啟的腳本代碼
放到crontab里一分鐘執(zhí)行一次。url和cmd根據自己的改。2010-12-12