Nginx限流特技
本文介紹了Nginx限流的技巧及三個實驗對比。
上篇文章回顧:Memcache使用Mcrouter實現高可用
限流(rate limiting)是Nginx眾多特性中最有用的,也是經常容易被誤解和錯誤配置的,特性之一。該特性可以限制某個使用者在一個給定時間段內能夠產生的HTTP請求數。請求可以簡單到就是一個對於主頁的GET請求或者一個登陸表格的POST請求。
限流可以用於安全目的上,透過限制請求速度來防止外部暴力掃描,或者減慢暴力密碼破解攻擊,可以結合日誌標記出目標URL來幫助防範DDoS攻擊,也可以解決流量突發的問題(如整點活動),一般地說,限流是用在保護上游應用伺服器不被在同一時刻的大量使用者請求湮沒。
我們在訪問內部域名時在1s時間內發起兩個請求,操作上的一些時差會出現兩種不同的結果,2個請求都返回200,或者1個請求返回200,而另外一個請求返回503,為此對Nginx限流模組進行了深入調研,Nginx在處理請求的時候是在1s內對請求的具體個數做拆分的,以2request/s為例,拆分為500ms內處理一個請求,下一個500ms才會處理第二個請求;除此之外,我們發現,在限制2request/s後,發現傳送多個請求(requests>=2)也可以被處理掉,在此基礎上上,調研了緩衝佇列的相關配置。
1 漏桶和令牌桶演算法的概念
漏桶演算法(Leaky Bucket):主要目的是控制資料注入到網路的速率,平滑網路上的突發流量。漏桶演算法提供了一種機制,透過它,突發流量可以被整形以便為網路提供一個穩定的流量。漏桶演算法的示意圖如下圖所示,請求先進入到漏桶裡,漏桶以一定的速度出水,當水請求過大會直接溢位,可以看出漏桶演算法能強行限制資料的傳輸速率。
令牌桶演算法(Token Bucket):是網路流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一種演算法。典型情況下,令牌桶演算法用來控制傳送到網路上的資料的數目,並允許突發資料的傳送。令牌桶演算法示意圖如下圖所示,大小固定的令牌桶可自行以恆定的速率源源不斷地產生令牌。如果令牌不被消耗,或者被消耗的速度小於產生的速度,令牌就會不斷地增多,直到把桶填滿。後面再產生的令牌就會從桶中溢位。最後桶中可以儲存的最大令牌數永遠不會超過桶的大小。
2 兩種演算法的區別
兩者主要區別在於“漏桶演算法”能夠強行限制資料的傳輸速率,而“令牌桶演算法”在能夠限制資料的平均傳輸速率外,還允許某種程度的突發傳輸。在“令牌桶演算法”中,只要令牌桶中存在令牌,那麼就允許突發地傳輸資料直到達到使用者配置的門限,所以它適合於具有突發特性的流量。
3 按請求速率限速
按請求速率限速是指限制IP傳送請求的速率,超出指定速率後,Nginx將直接拒絕更多的請求。採用漏桶演算法實現。下面從一些實驗資料上來深入的瞭解這個模組,先簡單介紹一下該模組的配置方式,如下圖所示(配置需要在Nginx配置和域名配置裡面同時修改),使用limit_req_zone關鍵字,定義一個名為tip大小為10MB的共享記憶體區域(zone),用來存放限速相關的統計資訊,限速的key值為二進位制的IP地址($binary_remote_addr),限速上限(rate)為2r/s。
將上述規則應用到/search目錄(單個IP的訪問速度被限制在了2請求/秒,超過這個限制的訪問將直接被Nginx拒絕)。burst和nodelay的作用稍後解釋。(zone=tip:10m表示會話空間的儲存大小為10m)。
4 3個實驗案例
實驗1、討論2個請求在1s內的執行過程
修改配置下圖所示:
我們使用ab工具模擬1s傳送2個請求。
只有一個請求成功了,檢視了一下執行時間:
1ms內完成了所有請求,考慮到每秒兩個請求可能是分時間段來來完成的,二分法做了大量延遲處理的嘗試,當兩個請求之間的時延大於0.5s時第二個請求才會成功。
結論:Nginx的限流統計是基於毫秒的,我們設定的速度是2r/s,轉換一下就是500ms內單個IP只允許透過1個請求,從501ms開始才允許透過第二個請求。
實驗2、burst允許快取處理突發請求
如果短時間內傳送了大量請求,Nginx按照毫秒級精度統計,超出限制的請求直接拒絕。這在實際場景中未免過於苛刻,真實網路環境中請求到來不是勻速的,很可能有請求“突發”的情況。Nginx考慮到了這種情況,可以透過burst關鍵字開啟對突發請求的快取處理,而不是直接拒絕。(類似令牌桶演算法)
修改Nginx配置如下:
我們加入了burst=4,意思是每個key(此處是每個IP)最多允許4個突發請求的到來。使用ab工具傳送6個請求,結果會怎樣呢?
傳送時間:
執行結果是請求全部被處理,加入緩衝佇列後,按照之前時間軸的規則 ,在0.001s、0.501s、1.001s、1.501s、2.001s、2.501s分別傳送一個請求,與之前的有些偏差,理論上資料應該是同時傳送到ngnix,我們做了抓包統進行驗證,可以觀察到6個請求分別開闢了6個埠進行傳送,只有當第一個包三次握手完成,第二個包才開始傳送,時間間隔500ms,這就驗證了ab工具確實是單個傳送的。
另外,理論上緩衝區之外的2個請求應該只有一個是200,另外一個是503,緩衝區的4個請求是按照2r/s的速度依次處理,這裡是由於ab工具本身的問題,在加入緩衝佇列後,傳送時間由之前的1ms內完成變成了2501ms完成,所以導致了請求都被處理掉,若是使用其他工具短時間內傳送6個請求,則只能成功5個。
傳送耗時2ms,完成處理時間2437ms,每個請求的處理時間。
由於ngnix 500ms處理完第一個請求後,501ms才會處理第二個請求,所以5個請求(去掉503那個)耗時500ms*4+416ms=2416ms(本地實測,不同Nginx效能有所差異),或者使用ab工具併發來處理這些請求,也會有同樣的效果。
我們再來觀察一下傳送時間,所有的請求基本在10ms內發起,這樣便導致了6個請求中,去掉第一個和緩衝區的4個,第二個被拒絕掉。
實驗3、nodelay降低排隊時間
透過設定burst引數,我們可以允許Nginx快取處理一定程度的突發,多餘的請求可以先放到佇列裡,慢慢處理,這起到了平滑流量的作用。但是如果佇列設定的比較大,請求排隊的時間就會比較長,這對使用者很不友好。nodelay引數允許請求在排隊的時候就立即被處理,也就是說只要請求能夠進入burst佇列,就會立即被後臺worker處理。
延續實驗2的配置,我們加入nodelay選項:
同樣傳送6個請求傳送時間:
實驗結果如下圖所示:
處理時間:
與實驗2相比直觀上的效果就是Nginx同時出現6條日誌,即6個請求是同時被處理的,而實驗2日誌是逐條生成的,間隔0.5s,視覺上有卡頓。
雖然設定burst和nodelay能夠降低突發請求的處理時間,但是長期來看並不會提高吞吐量的上限,長期吞吐量的上限是由rate決定的,因為nodelay只能保證burst的請求被立即處理,加入了nodelay引數之後的限速演算法還算是漏桶演算法,當令牌桶演算法的token為耗盡時,由於它有一個請求佇列,所以會把接下來的請求快取下來,快取多少受限於佇列大小。假如server已經過載,快取佇列越來越長,即使過了很久請求被處理了,對使用者來說也沒什麼價值了。所以當token不夠用時,最明智的做法就是直接拒絕使用者的請求,即漏桶演算法。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559359/viewspace-2220618/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 聊聊高併發系統之限流特技
- Nginx限流Nginx
- Nginx分片限流Nginx
- nginx之 nginx限流配置Nginx
- nginx 限流配置Nginx
- nginx做限流設定Nginx
- Nginx原始碼研究之nginx限流模組詳解Nginx原始碼
- Linux下玩轉nginx系列(七)---nginx如何實現限流功能LinuxNginx
- Nginx使用篇:實現負載均衡、限流與動靜分離Nginx負載
- 聊聊高併發系統之降級特技
- Visual C++中的圖形特技 (轉)C++
- Java常用中介軟體之 NGINX實現限流功能的官方文件說明JavaNginx
- Nginx R31 doc-13-Limiting Access to Proxied HTTP Resources 訪問限流NginxMITHTTP
- 介面限流
- 單機限流和分散式應用限流分散式
- 限流場景&限流方案的一些思考
- Guava RateLimiter限流GuavaMIT
- 分散式限流分散式
- 高可用之限流-03-Semaphore 訊號量做限流
- Redis 應用-限流Redis
- 淺談Api限流API
- 介面限流實踐
- Java Redis多限流JavaRedis
- 【高併發】面試官問我如何使用Nginx實現限流,我如此回答輕鬆拿到了Offer!面試Nginx
- sbc(四)應用限流
- Sentinel 實戰-限流篇
- 使用Redis進行限流Redis
- 常用限流演算法演算法
- 微服務 - Nginx閘道器 · 程式機制 · 限流熔斷 · 效能最佳化 · 動態負載 · 高可用微服務Nginx負載
- 5種限流演算法,7種限流方式,擋住突發流量?演算法
- Guava RateLimiter限流器使用示例GuavaMIT
- go-kit微服務:限流Go微服務
- 簡析限流演算法演算法
- 限流演算法介紹演算法
- redis實際應用-限流Redis
- AspNetCore新增API限流NetCoreAPI
- Spring Cloud Gateway 限流操作SpringCloudGateway
- 專案如何實現限流?