一,limit_req的用途:
1,官方文檔地址:
http://nginx.org/en/docs/http/ngx_http_limit_req_module.html
2,用途:
限制用戶在給定時間內HTTP請求的數量,
流量限制主要用作安全目的,
可以防止大量請求的攻擊下服務被壓垮,
可以減慢暴力密碼破解的速率
3,原理:漏桶算法
在limit_req的限制下,請求被nginx以固定的速率處理,這個符合漏桶算法,
即流出的速率恆定。
說明:劉宏締的架構森林是一個專注架構的博客,地址:https://www.cnblogs.com/architectforest
對應的源碼可以訪問這里獲取: https://github.com/liuhongdi/
說明:作者:劉宏締 郵箱: 371125307@qq.com
二,limit_req的配置舉例:
1,常用的兩個指令:
nginx.conf中
limit_req_zone:定義到http區域:
limit_req_zone $binary_remote_addr zone=perip:20m rate=1r/s;
limit_req:定義到server或location區域
limit_req zone=perip;
說明:
變量:$binary_remote_addr,這里是客戶端的ip地址,
在這里是做限制的標識,是基於ip地址來限制
zone=perip:20m: perip是內存區域的名字,
20m: 生成的內存區域的大小
rate=1r/s: 允放相同標識的客戶端的訪問頻次,
在這個例子中:就是同一個ip地址在每秒內只能訪問1次
2,例子一:以每秒處理1個請求的速率做限制
limit_req_zone $binary_remote_addr zone=perip:10m rate=1r/s;
...
limit_req zone=perip;
重啟 nginx后測試:
[liuhongdi@centos8 logs]$ ab -c 10 -n 10 http://www.lhdtest.com/index.html ... Concurrency Level: 10 Time taken for tests: 0.002 seconds Complete requests: 10 Failed requests: 9 (Connect: 0, Receive: 0, Length: 9, Exceptions: 0) Non-2xx responses: 9 ...
只有一個成功,有9個請求失敗
時長是0.002 seconds
3,例子2:burst
增加burst,再次測試
limit_req_zone $binary_remote_addr zone=perip:10m rate=1r/s; ... limit_req zone=perip burst=2;
說明:burst=2 允許2個突發,
有大量請求時,超過頻次限制的請求,會允許2個訪問,
注意:burst指定的請求數量,不會馬上進行處理,
而是按照rate指定的值,以固定的速率進行處理。
以10個並發請求為例:
rate= 1r/s
就是先處理1個,剩下的9個中,
7個請求,直接返回503
剩下的2個放到突發的隊列中延遲執行,
仍然按rate= 1r/s進行處理,所以需要約兩秒的等待時間
[liuhongdi@centos8 logs]$ ab -c 10 -n 10 http://www.lhdtest.com/index.html ... Concurrency Level: 10 Time taken for tests: 2.004 seconds Complete requests: 10 Failed requests: 7 (Connect: 0, Receive: 0, Length: 7, Exceptions: 0) Non-2xx responses: 7 ...
有7個請求失敗
注意時間變成了2.004 seconds
4,例子三:nodelay
limit_req_zone $binary_remote_addr zone=perip:10m rate=1r/s; ... limit_req zone=perip burst=2 nodelay;
說明:
nodelay參數:
burst的隊列雖然可以處理用戶的需求,但需要用戶按照處理時間等待,對用戶不夠友好,
nodelay參數允許請求在排隊的時候就立即被處理,
這里有一點要注意:因為nodelay允許立即處理,也就是有並發請求時
事實上已經超過了rate設置的處理速率了,
所以要根據自己機器的實際情況設置這個值
理解nodelay:
nodelay只是對放到burst隊列中的請求立即處理,
但處理完成后隊列並不立即清空,
隊列清空的速度仍然按原來的速度每秒一個清空,
所以當再有請求過來時,並不會馬上又有兩個burst請求被處理.
再次測試
[liuhongdi@centos8 logs]$ ab -c 10 -n 10 http://www.lhdtest.com/index.html ... Concurrency Level: 10 Time taken for tests: 0.002 seconds Complete requests: 10 Failed requests: 7 (Connect: 0, Receive: 0, Length: 7, Exceptions: 0) Non-2xx responses: 7 ...
有7個請求失敗
注意時間:這次是0.002 seconds
三,rate和burst應該設置為多少?
1,網站需要把動態生成的內容(java,php,python等程序生成)和靜態內容分離到不同的虛擬主機
因為靜態內容不需要大量的計算,
通常limit_req用於限制動態內容的訪問頻率
2,限流的目的不是讓用戶不能訪問,
而是為了保證用戶能流暢的訪問,
所以需要根據頁面的實際情況來限制
如果一個頁面打開時同時發出的請求比較多,
(靜態文件分離后要檢查ajax請求數,
可以根據生產環境的日志進行檢查)
則rate值不能低於並發的請求數.
如果低於並發的情求數,會導致用戶不能正常訪問頁面
3,我們在生產環境中的例子,僅供參考
limit_req_zone $binary_remote_addr zone=reqperip:20m rate=20r/s; limit_req zone=reqperip burst=10 nodelay;
四,其他可配置的參數:
1,limit_req_status用來指定請求時報錯產生的狀態碼:
limit_req_status 這個值默認是503,
可以指定為一個自定義的值,
例如:444
說明:444是nginx自定義的一個非標准狀態碼,
它會立即關閉連接,連響應頭也不給客戶端發
可以在受到惡意攻擊時使用這個狀態碼
2,limit_req_log_level 當報錯時記錄到日志的錯誤級別,
默認值是error
可選值: info
| notice
| warn
| error
不建議改動這個值
五,查看nginx的版本:
[root@centos8 conf.d]# /usr/local/soft/nginx-1.18.0/sbin/nginx -v
nginx version: nginx/1.18.0