1乘碑、限流算法
令牌桶算法
算法思想是:
a、令牌以固定速率產(chǎn)生金拒,并緩存到令牌桶中兽肤;
b、令牌桶放滿時(shí)绪抛,多余的令牌被丟棄资铡;
c、請求要消耗等比例的令牌才能被處理幢码;
d笤休、令牌不夠時(shí),請求被緩存症副。
漏桶算法
算法思想是:
a店雅、水(請求)從上方倒入水桶,從水桶下方流出(被處理)贞铣,來不及流出的水存在水桶中(緩沖)闹啦,以固定速率流出;
b辕坝、水桶滿后水溢出(丟棄)窍奋。
這個(gè)算法的核心是:緩存請求、勻速處理酱畅、多余的請求直接丟棄琳袄。
相比漏桶算法,令牌桶算法不同之處在于它不但有一只“桶”纺酸,還有個(gè)隊(duì)列窖逗,這個(gè)桶是用來存放令牌的,隊(duì)列才是用來存放請求的吁峻。
從作用上來說滑负,漏桶和令牌桶算法最明顯的區(qū)別就是是否允許突發(fā)流量(burst)的處理,漏桶算法能夠強(qiáng)行限制數(shù)據(jù)的實(shí)時(shí)傳輸(處理)速率用含,對突發(fā)流量不做額外處理;而令牌桶算法能夠在限制數(shù)據(jù)的平均傳輸速率的同時(shí)允許某種程度的突發(fā)傳輸帮匾。
2啄骇、限流配置
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
server {
location / {
limit_req zone=mylimit;
proxy_pass http://my_upstream;
}
}
參數(shù)解釋:
1、 $binary_remote_addr — nginx變量瘟斜,該變量代表了某個(gè)客戶端IP地址的二進(jìn)制形式缸夹。這意味著我們可以將每個(gè)特定的IP地址的請求速率限制為第三個(gè)參數(shù)所定義的值痪寻。(使用這個(gè)變量的原因是因?yàn)樗扔胹tring代表客戶端IP地址的$remote_addr變量消耗更少的空間。)
2虽惭、Zone — 定義了存儲每個(gè)IP地址狀態(tài)和它訪問受限請求URL的頻率的共享內(nèi)存區(qū)域橡类。將這些信息保存在共享內(nèi)存中,意味著這些信息能夠在nginx工作進(jìn)程之間共享芽唇。定義有兩個(gè)部分:由zone=關(guān)鍵字標(biāo)識的區(qū)域名稱顾画,以及冒號后面的區(qū)域大小。約16000個(gè)IP地址的狀態(tài)信息消耗1M內(nèi)存大小匆笤,因此我們的區(qū)域(zone)大概可以存儲約160000個(gè)地址研侣。當(dāng)nginx需要添加新的記錄時(shí),如果此時(shí)存儲耗盡了炮捧,最老的記錄會被移除庶诡。如果釋放的存儲空間還是無法容納新的記錄,nginx返回503 (Service Temporarily Unavailable)狀態(tài)碼咆课。此外末誓,為了防止內(nèi)存被耗盡,每次nginx創(chuàng)建一個(gè)新的記錄的同時(shí)移除多達(dá)兩條前60秒內(nèi)沒有被使用的記錄书蚪。
3基显、Rate — 設(shè)置最大的請求速率。在上面的例子中善炫,速率不能超過10個(gè)請求每秒撩幽。NGINX事實(shí)上可以在毫秒級別追蹤請求,因此這個(gè)限制對應(yīng)了1個(gè)請求每100毫秒箩艺。因?yàn)槲覀儾辉试S突刺(bursts窜醉,短時(shí)間內(nèi)的突發(fā)流量,詳細(xì)見下一部分艺谆。)榨惰,這意味著如果某個(gè)請求到達(dá)的時(shí)間離前一個(gè)被允許的請求小于100毫秒,它會被拒絕静汤。
注意:imit_req_zone指令設(shè)置限流和共享內(nèi)存區(qū)域的參數(shù)琅催,但是該指令實(shí)際上并不限制請求速率。為了限制起作用虫给,需要將該限制應(yīng)用到某個(gè)特定的location或server塊(block)藤抡,通過包含一個(gè)limit_req指令的方式。
3抹估、處理流量突刺(Bursts)
如果在100毫秒內(nèi)得到2個(gè)請求會怎么樣缠黍?對于第2個(gè)請求,NGINX返回503狀態(tài)碼給客戶端药蜻。這可能不是我們想要的瓷式,因?yàn)槭聦?shí)上替饿,應(yīng)用是趨向于突發(fā)性的。相反贸典,我們想要緩存任何過多的請求并且及時(shí)地服務(wù)它們视卢。
location / {
limit_req zone=mylimit burst=20;
proxy_pass http://my_upstream;
}
burst參數(shù)定義了一個(gè)客戶端能夠產(chǎn)生超出區(qū)域(zone)規(guī)定的速率的請求數(shù)量(在我們示例mylimit區(qū)域中,速率限制是10個(gè)請求每秒廊驼,或1個(gè)請求每100毫秒)据过。一個(gè)請求在前一個(gè)請求后的100毫秒間隔內(nèi)達(dá)到,該請求會被放入一個(gè)隊(duì)列蔬充,并且該隊(duì)列大小被設(shè)置為20蝶俱。這意味著如果從某個(gè)特定IP地址來的21個(gè)請求同時(shí)地達(dá)到,NGINX立即轉(zhuǎn)發(fā)第一個(gè)請求到上游的服務(wù)器組饥漫,并且將剩余的20個(gè)請求放入隊(duì)列中榨呆。然后,NGINX每100毫秒轉(zhuǎn)發(fā)一個(gè)隊(duì)列中的請求庸队,并且只有當(dāng)某個(gè)新進(jìn)來的請求使得隊(duì)列中的請求數(shù)目超過了20积蜻,則返回503給客戶端。
無延遲排隊(duì)
帶有burst的配置產(chǎn)生平滑的網(wǎng)絡(luò)流量彻消,但是不實(shí)用竿拆,因?yàn)樵撆渲脮沟媚愕木W(wǎng)站表現(xiàn)的很慢。在上面的例子中宾尚,隊(duì)列中第20個(gè)數(shù)據(jù)包等待2秒才能被轉(zhuǎn)發(fā)丙笋,這時(shí)該數(shù)據(jù)包的響應(yīng)可能對于客戶端已經(jīng)沒有了意義。為了處理這種情況煌贴,除了burst參數(shù)外御板,添加nodelay參數(shù)。
location /login/ {
limit_req zone=mylimit burst=20 nodelay;
proxy_pass http://my_upstream
}