前言
每逢大促必壓測,每逢大促必限流,這估計是電商人的常態。每次大促期間,業務流量是平時的幾倍十幾倍,大促期間大部分業務都會集中在購物車結算,必須限流,才能保證系統不宕機。
限流算法
限流算法一般有三種:令牌桶,漏桶,計數器。本文介紹最粗暴的計數器算法,其他算法請自行google、百度,講的應該比我好。(能解決問題的算法都是好算法)
lua 限流
業務結構
在大促期間由於流量過高,現有服務器無法承受那么大的流量,租用雲服務是很好的選擇。
業務架構圖可以看出 ,我們的服務器有自有服務器,首都在線雲,金山雲。自有服務器由於采購時間原因,每個批次的服務器性能不是很一致,首都在線雲、金山雲的服務器性能又有很大的差別,
lvs在權重設置上也有很大的不同,這對我們使用lua限流又造成了一定的困擾。當然這只是小問題,既然lvs只是權重,那么我們的lua限流也支持權重即可。
nginx+lua
使用nginx+lua的原因很簡單,我們服務架構nginx+fastcgi+php,為了防止php進程被打滿,我們只需要在nginx加一層限制,就可以簡單粗暴的解決問題,而lua正好滿足這個條件。業務場景的不同,我們選擇的算法也不同,越是復雜的東西,越希望最簡單話的解決方案。引入越多的東西,就會造成更多的不確定性。
話不多說上代
ngx.header.content_type = "text/html; charset=utf-8"; local method=ngx.req.get_method() local curl=ngx.md5(ngx.var.request_uri); local request_uri_without_args = ngx.re.sub(ngx.var.request_uri, "\\?.*", ""); local match = string.match local ngxmatch=ngx.re.match --限流計數 function limit_url_check(key,s,m) local localkey=key; local yyy_limit=ngx.shared.url_limit --每分鍾限制 local key_m_limit= localkey..os.date("%Y-%m-%d %H:%M", ngx.time()) --每秒限制 local key_s_limit= localkey..os.date("%Y-%m-%d %H:%M:%S", ngx.time()) local req_key,_=yyy_limit:get(localkey); local req_key_s,_=yyy_limit:get(key_s_limit); local req_key_m,_=yyy_limit:get(key_m_limit); --每秒處理 if req_key_s then yyy_limit:incr(key_s_limit,1) if req_key_s>s then --return true return false end else yyy_limit:set(key_s_limit,1,60) end --每分鍾處理 if req_key_m then yyy_limit:incr(key_m_limit,1) if req_key_m>m then --return true return false end else yyy_limit:set(key_m_limit,1,85) end return false end
代碼很簡單,但是很實用,看一下調用
if ngx.re.match(request_uri_without_args,"/cart/inf(.*)") then if limit_url_check("appcartinfo",24,3200) then ngx.say('{"code": 524,"msg": "啊啊啊,每逢大促,排隊結賬。當前訪問的用戶過多,請稍后再試!","alert": "啊啊啊,每逢大促,排隊結賬。當前訪問的用戶過多,請稍后再試!"}') ngx.exit(200); return end end
調用的代碼秒,分鍾的限制數可以放到cjson中配置。
以上,歡迎大神給出意見建議。