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