nginx?流控使用的項(xiàng)目實(shí)踐
正常限制訪問(wèn)頻率(正常流量)
流量限制”配置兩個(gè)主要的指令,limit_req_zone和limit_req,如下所示:
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s; server { location /login/ { limit_req zone=mylimit; proxy_pass http://my_upstream; } }
limit_req_zone指令定義了流量限制相關(guān)的參數(shù),而limit_req指令在出現(xiàn)的上下文中啟用流量限制(示例中,對(duì)于”/login/”的所有請(qǐng)求)。limit_req_zone指令通常在 HTTP 塊中定義,使其可在多個(gè)上下文中使用,它需要以下三個(gè)參數(shù):
1)Key - 定義應(yīng)用限制的請(qǐng)求特性。示例中的 Nginx 變量remote_addr,占用更少的空間)
2)Zone - 定義用于存儲(chǔ)每個(gè) IP 地址狀態(tài)以及被限制請(qǐng)求 URL 訪問(wèn)頻率的共享內(nèi)存區(qū)域。保存在內(nèi)存共享區(qū)域的信息,意味著可以在 Nginx 的 worker 進(jìn)程之間共享。定義分為兩個(gè)部分:通過(guò)zone=keyword標(biāo)識(shí)區(qū)域的名字,以及冒號(hào)后面跟區(qū)域大小。16000 個(gè) IP 地址的狀態(tài)信息,大約需要 1MB,所以示例中區(qū)域可以存儲(chǔ) 160000 個(gè) IP 地址。
3)Rate - 定義最大請(qǐng)求速率。在示例中,速率不能超過(guò)每秒 10 個(gè)請(qǐng)求。Nginx 實(shí)際上以毫秒的粒度來(lái)跟蹤請(qǐng)求,所以速率限制相當(dāng)于每 100 毫秒 1 個(gè)請(qǐng)求。因?yàn)椴辉试S”突發(fā)情況”,這意味著在前一個(gè)請(qǐng)求 100 毫秒內(nèi)到達(dá)的請(qǐng)求將被拒絕。
當(dāng) Nginx 需要添加新條目時(shí)存儲(chǔ)空間不足,將會(huì)刪除舊條目。如果釋放的空間仍不夠容納新記錄,Nginx 將會(huì)返回 503狀態(tài)碼(Service Temporarily Unavailable)。另外,為了防止內(nèi)存被耗盡,Nginx 每次創(chuàng)建新條目時(shí),最多刪除兩條 60 秒內(nèi)未使用的條目。
limit_req_zone指令設(shè)置流量限制和共享內(nèi)存區(qū)域的參數(shù),但實(shí)際上并不限制請(qǐng)求速率。所以需要通過(guò)添加limit_req指令,將流量限制應(yīng)用在特定的 location 或者 server 塊。在上面示例中,我們對(duì)/login/請(qǐng)求進(jìn)行流量限制。
現(xiàn)在每個(gè) IP 地址被限制為每秒只能請(qǐng)求 10 次 /login/,更準(zhǔn)確地說(shuō),在前一個(gè)請(qǐng)求的 100 毫秒內(nèi)不能請(qǐng)求該 URL。
突發(fā)限制訪問(wèn)頻率(突發(fā)流量)
如果我們?cè)?100 毫秒內(nèi)接收到 2 個(gè)請(qǐng)求,怎么辦?對(duì)于第二個(gè)請(qǐng)求,Nginx 將給客戶端返回狀態(tài)碼 503。這可能并不是我們想要的結(jié)果,因?yàn)閼?yīng)用本質(zhì)上趨向于突發(fā)性。相反地,我們希望緩沖任何超額的請(qǐng)求,然后及時(shí)地處理它們。我們更新下配置,在limit_req中使用 burst 參數(shù):
location /login/ { limit_req zone=mylimit burst=20; proxy_pass http://my_upstream; }
burst 參數(shù)定義了超出 zone 指定速率的情況下(示例中的 mylimit 區(qū)域,速率限制在每秒 10 個(gè)請(qǐng)求,或每 100 毫秒一個(gè)請(qǐng)求),客戶端還能發(fā)起多少請(qǐng)求。上一個(gè)請(qǐng)求 100 毫秒內(nèi)到達(dá)的請(qǐng)求將會(huì)被放入隊(duì)列,我們將隊(duì)列大小設(shè)置為 20。
這意味著,如果從一個(gè)給定 IP 地址發(fā)送 21 個(gè)請(qǐng)求,Nginx 會(huì)立即將第一個(gè)請(qǐng)求發(fā)送到上游服務(wù)器群,然后將余下 20 個(gè)請(qǐng)求放在隊(duì)列中。然后每 100 毫秒轉(zhuǎn)發(fā)一個(gè)排隊(duì)的請(qǐng)求,只有當(dāng)傳入請(qǐng)求使隊(duì)列中排隊(duì)的請(qǐng)求數(shù)超過(guò) 20 時(shí),Nginx 才會(huì)向客戶端返回 503。
無(wú)延遲的排隊(duì)
配置 burst 參數(shù)將會(huì)使通訊更流暢,但是可能會(huì)不太實(shí)用,因?yàn)樵撆渲脮?huì)使站點(diǎn)看起來(lái)很慢。在上面的示例中,隊(duì)列中的第 20 個(gè)包需要等待 2 秒才能被轉(zhuǎn)發(fā),此時(shí)返回給客戶端的響應(yīng)可能不再有用。要解決這個(gè)情況,可以在 burst 參數(shù)后添加 nodelay 參數(shù):
location /login/ { limit_req zone=mylimit burst=20 nodelay; proxy_pass http://my_upstream; }
使用 nodelay 參數(shù),Nginx 仍將根據(jù) burst 參數(shù)分配隊(duì)列中的位置,并應(yīng)用已配置的速率限制,而不是清理隊(duì)列中等待轉(zhuǎn)發(fā)的請(qǐng)求。相反地,當(dāng)一個(gè)請(qǐng)求到達(dá)“太早”時(shí),只要在隊(duì)列中能分配位置,Nginx 將立即轉(zhuǎn)發(fā)這個(gè)請(qǐng)求。將隊(duì)列中的該位置標(biāo)記為”taken”(占據(jù)),并且不會(huì)被釋放以供另一個(gè)請(qǐng)求使用,直到一段時(shí)間后才會(huì)被釋放(在這個(gè)示例中是,100 毫秒后)。
假設(shè)如前所述,隊(duì)列中有 20 個(gè)空位,從給定的 IP 地址發(fā)出的 21 個(gè)請(qǐng)求同時(shí)到達(dá)。Ngin x會(huì)立即轉(zhuǎn)發(fā)這個(gè) 21 個(gè)請(qǐng)求,并且標(biāo)記隊(duì)列中占據(jù)的 20 個(gè)位置,然后每 100 毫秒釋放一個(gè)位置。如果是25個(gè)請(qǐng)求同時(shí)到達(dá),Nginx 將會(huì)立即轉(zhuǎn)發(fā)其中的 21 個(gè)請(qǐng)求,標(biāo)記隊(duì)列中占據(jù)的 20 個(gè)位置,并且返回 503 狀態(tài)碼來(lái)拒絕剩下的 4 個(gè)請(qǐng)求。
現(xiàn)在假設(shè),第一組請(qǐng)求被轉(zhuǎn)發(fā)后 101 毫秒,另 20 個(gè)請(qǐng)求同時(shí)到達(dá)。隊(duì)列中只會(huì)有一個(gè)位置被釋放,所以 Nginx 轉(zhuǎn)發(fā)一個(gè)請(qǐng)求并返回503狀態(tài)碼來(lái)拒絕其他 19 個(gè)請(qǐng)求。如果在 20 個(gè)新請(qǐng)求到達(dá)之前已經(jīng)過(guò)去了 501 毫秒,5 個(gè)位置被釋放,所以 Nginx 立即轉(zhuǎn)發(fā) 5 個(gè)請(qǐng)求并拒絕另外 15 個(gè)。
效果相當(dāng)于每秒 10 個(gè)請(qǐng)求的“流量限制”。如果希望不限制兩個(gè)請(qǐng)求間允許間隔的情況下實(shí)施“流量限制”,nodelay 參數(shù)是很實(shí)用的。
注意:對(duì)于大部分部署,我們建議使用 burst 和 nodelay 參數(shù)來(lái)配置limit_req指令。
限制并發(fā)連接數(shù)
Nginx 的ngx_http_limit_conn_module模塊提供了對(duì)資源連接數(shù)進(jìn)行限制的功能,使用 limit_conn_zone 和 limit_conn 兩個(gè)指令就可以了。
properties復(fù)制代碼limit_conn perip 20 : 對(duì)應(yīng)的key是 $binary_remote_addr,表示限制單個(gè)IP同時(shí)最多能持有20個(gè)連接。
limit_conn perserver 100 : 對(duì)應(yīng)的key是 $server_name,表示虛擬主機(jī)(server) 同時(shí)能處理并發(fā)連接的總數(shù)。注意,只有當(dāng) request header 被后端server處理后,這個(gè)連接才進(jìn)行計(jì)數(shù)。
修改nginx.conf配置,如下:
#速率限流配置 limit_req_zone $binary_remote_addr zone=ipRateLimit:10m rate=2r/s; #并發(fā)量限流-單個(gè)IP控制 limit_conn_zone $binary_remote_addr zone=perip:10m; #并發(fā)量限流-整個(gè)服務(wù)控制 limit_conn_zone $server_name zone=perserver:10m; server { listen 80; server_name localhost; location ~ .*\.(woff|ico|css|js|gif|jpg|jpeg|png)$ { root /usr/local/openrestyDir/pages/; } location /msitems/ { #限流配置 #limit_req zone=ipRateLimit burst=5 nodelay; #并發(fā)量限流 limit_conn perip 10; limit_conn perserver 100; root /usr/local/openrestyDir/pages/; } }
上面配置了單個(gè)IP同時(shí)并發(fā)連接數(shù)最多只能10個(gè)連接,并且設(shè)置了整個(gè)虛擬服務(wù)器同時(shí)最大并發(fā)數(shù)最多只能100個(gè)鏈接。當(dāng)然,只有當(dāng)請(qǐng)求的header被服務(wù)器處理后,虛擬服務(wù)器的連接數(shù)才會(huì)計(jì)數(shù)。剛才有提到過(guò)Nginx是基于漏桶算法原理實(shí)現(xiàn)的,實(shí)際上限流一般都是基于漏桶算法和令牌桶算法實(shí)現(xiàn)的。接下來(lái)我們來(lái)看看兩個(gè)算法的介紹:
漏桶算法
漏桶算法是網(wǎng)絡(luò)世界中流量整形或速率限制時(shí)經(jīng)常使用的一種算法,它的主要目的是控制數(shù)據(jù)注入到網(wǎng)絡(luò)的速率,平滑網(wǎng)絡(luò)上的突發(fā)流量。漏桶算法提供了一種機(jī)制,通過(guò)它,突發(fā)流量可以被整形以便為網(wǎng)絡(luò)提供一個(gè)穩(wěn)定的流量。也就是我們剛才所講的情況。漏桶算法提供的機(jī)制實(shí)際上就是剛才的案例:突發(fā)流量會(huì)進(jìn)入到一個(gè)漏桶,漏桶會(huì)按照我們定義的速率依次處理請(qǐng)求,如果水流過(guò)大也就是突發(fā)流量過(guò)大就會(huì)直接溢出,則多余的請(qǐng)求會(huì)被拒絕。所以漏桶算法能控制數(shù)據(jù)的傳輸速率。
令牌桶算法
令牌桶算法是網(wǎng)絡(luò)流量整形和速率限制中最常使用的一種算法。典型情況下,令牌桶算法用來(lái)控制發(fā)送到網(wǎng)絡(luò)上的數(shù)據(jù)的數(shù)目,并允許突發(fā)數(shù)據(jù)的發(fā)送。Google開(kāi)源項(xiàng)目Guava中的RateLimiter使用的就是令牌桶控制算法。令牌桶算法的機(jī)制如下:存在一個(gè)大小固定的令牌桶,會(huì)以恒定的速率源源不斷產(chǎn)生令牌。如果令牌消耗速率小于生產(chǎn)令牌的速度,令牌就會(huì)一直產(chǎn)生直至裝滿整個(gè)令牌桶。
黑白名單
有時(shí)候會(huì)有一些惡意IP攻擊服務(wù)器,會(huì)基于程序頻繁發(fā)起請(qǐng)求對(duì)服務(wù)器造成巨大壓力,我們此時(shí)可以使用Nginx的黑名單功能實(shí)現(xiàn)黑名單過(guò)濾操作。我們首先需要配置黑名單IP,黑名單IP我們可以記錄到一個(gè)配置文件中,比如配置到blockip.conf文件中:
配置固定IP為黑名單:
deny 192.168.100.1;
在nginx.conf中引入blockip.conf,可以放到http, server, location語(yǔ)句塊,配置如下:
#黑名單 include blockip.conf;
此時(shí)在192.168.100.1的IP上訪問(wèn)服務(wù)器,會(huì)報(bào)403錯(cuò)誤
屏蔽ip的配置文件既可以屏蔽單個(gè)ip,也可以屏蔽ip段,或者只允許某個(gè)ip或者某個(gè)ip段訪問(wèn)。
# 屏蔽單個(gè)ip訪問(wèn) deny IP; # 允許單個(gè)ip訪問(wèn) allow IP; # 屏蔽所有ip訪問(wèn) deny all; # 允許所有ip訪問(wèn) allow all; #屏蔽整個(gè)段即從123.0.0.1到123.255.255.254訪問(wèn)的命令 deny 123.0.0.0/8 #屏蔽IP段即從123.45.0.1到123.45.255.254訪問(wèn)的命令 deny 124.45.0.0/16 #屏蔽IP段即從123.45.6.1到123.45.6.254訪問(wèn)的命令 deny 123.45.6.0/24
如果你想實(shí)現(xiàn)這樣的應(yīng)用,除了幾個(gè)IP外,其他全部拒絕,那需要你在blockip.conf中這樣寫(xiě):
allow 192.168.100.1; allow 192.168.100.2; deny all;
但是這種手動(dòng)配置的方式可能太過(guò)繁瑣,我們也可以配置動(dòng)態(tài)黑白名單。
配置動(dòng)態(tài)黑白名單,我們可以采用Lua+Redis實(shí)現(xiàn),將黑名單存入到Redis緩存,每次執(zhí)行請(qǐng)求時(shí),通過(guò)lua腳本先獲取用戶IP,匹配IP是否屬于黑名單,如果是,則不讓請(qǐng)求,如果不是,則放行。
參考鏈接:
https://juejin.cn/post/7120044094239277070
https://cloud.tencent.com/developer/article/1912141
到此這篇關(guān)于nginx 流控使用的項(xiàng)目實(shí)踐的文章就介紹到這了,更多相關(guān)nginx 流控內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
nginx高可用集群的實(shí)現(xiàn)過(guò)程
這篇文章主要介紹了nginx高可用集群的實(shí)現(xiàn)過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10Nginx如何實(shí)現(xiàn)pathinfo模式的方法詳解
pathinfo是偽靜態(tài)的一種,對(duì)于用過(guò)thinkphp的朋友們來(lái)說(shuō)應(yīng)該都不陌生,下面這篇文章主要給大家介紹了關(guān)于Nginx如何實(shí)現(xiàn)pathinfo模式的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下。2017-09-09nginx部署后css、js、圖片等樣式不加載問(wèn)題的兩種解決方案
這篇文章主要介紹了nginx部署后css、js、圖片等樣式不加載問(wèn)題的兩種解決方案,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-12-12Nginx基礎(chǔ)location語(yǔ)法及功能配置實(shí)例
這篇文章主要為大家介紹了Nginx基礎(chǔ)location語(yǔ)法及功能以及配置實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03實(shí)現(xiàn)自動(dòng)定期刪除Nginx日志的方法
這篇文章主要介紹了自動(dòng)定期刪除Nginx日志的方法,Nginx是一個(gè)基于事務(wù)的異步的高速服務(wù)器軟件,需要的朋友可以參考下2015-07-07詳解Nginx中的geo模塊與利用其配置負(fù)載均衡的示例
這篇文章主要介紹了詳解Nginx中的geo模塊與利用其配置負(fù)載均衡的示例,文中對(duì)模塊的geo指令使用有比較詳細(xì)的介紹,需要的朋友可以參考下2016-01-01