Nginx請求連接限制


Nginx的請求限制

在配置nginx的過程中我們需要考慮受到攻擊或惡意請求的情況,比如單用戶惡意發起大量請求,這時Nginx的請求限制可以幫助我們對其進行限制。

連接頻率限制 : limit_conn_module

請求頻率限制 : limit_req_module

理解:連接頻率限制和請求頻率限制都可以實現Nginx的請求限制 , 但是他們的實現原理是不一樣的 , 區別就在於連接和請求上 , http協議的鏈接與請求 , http協議是建立在tcp協議之上的,要完成一次http的請求,先要進行tcp的3次握手建立http的連接 , 然后才進行http的request和response(請求和響應) , 現在http1.1以上的版本已經可以實現一次建立http的連接進行多次的http的request和response(請求和響應) ,最后客戶端和服務端不斷的來發送FIN包和ACK包來保持HTTP的連接 。

如果面對搶購和秒殺需求來限制 , 個人覺得連接頻率限制和請求頻率限制應該配合使用 , 使用連接頻率限制同一IP同時只能有3個連接, 再使用請求頻率限制對於同一ip的請求,限制平均速率為5個請求/秒 , 這樣是不是比單獨只使用一種限制要好很多?

比如只使用連接頻率限制 , 由於一次建立http的連接可以進行多次的請求和響應 , 我們無法精確的限制同一ip同時發起多少次的http請求 ;

比如只使用請求頻率限制 , 可以精確的限制同一ip1秒只能發起5次的http請求 , 假如同一ip1秒內發起了100000次請求 , 雖然限制了只有5次成功響應 , 但是其他的99995次的請求TCP握手建立http連接是不是會消耗服務器資源?

所以,個人覺得連接頻率限制和請求頻率限制應該配合使用!


HTTP協議的連接與請求

HTTP請求建立在一次TCP連接基礎上

一次TCP連接至少產生一次HTTP請求


連接限制

ngx_http_limit_conn_module模塊用於限制每個定義鍵的連接數,特別是來自單個IP地址的連接數。

配置示例

http {

...

#對單個ip、單個會話同時存在的連接數的限制。這里定義一個存儲區conn_zone,conn_zone的容量是1m,該存儲區針對於變量$binary_remote_add生效,這里是針對單個IP生效。該模塊只是一個定義,配置在http配置段,需要配合limit_conn指令使用才生效, limit_conn one 1表示該location段使用conn_zone定義的 limit_conn_zone ,對單個IP限制同時存在一個連接。

limit_conn_zone $binary_remote_addr zone=conn_zone:1m;

server {

​ location / {

​ limit_conn conn_zone 1;

​ }

}

做個演示:

未開啟連接限制時做個壓力測試
1、安裝ab測試命令
yum install httpd-tools -y

2、ab 參數
	-n : 總共需要訪問多少次
	-c : 每次訪問多少個

ab -n 10000 -c 1000 http://192.168.58.100/index.html

Complete requests: 10000

Failed requests: 78

這里模擬了10萬個請求 , 1000個並發 , 78個請求失敗,打開nginx的錯誤日志查看都是打開文件失敗的錯誤 ( open() "/usr/share/nginx/html/50x.html" failed (24: Too many open files))! 想象一下 , 如果我們是一個商城程序的API接口 , 正常情況下 , 同一個IP下10萬個請求1000個並發 , 算不算惡意攻擊?那么就需要做一下連接限制了噻 , 具體怎么限制根絕具體的邏輯去處理 , 我們這里簡單的限制一下(啟用配置示例的連接限制)再次做個壓力測試:

ab -n 10000 -c 1000 http://192.168.58.100/index.html

Complete requests: 100000

Failed requests: 43616

開啟連接限制對單個IP限制同時只能存在一個連接,這里模擬了10萬個請求 , 1000個並發 , 43616個請求失敗,打開nginx的錯誤日志查看下錯誤全是連接限制的作用(limiting connections by zone "conn_zone") , 我們知道"現在http1.1以上的版本已經可以實現一次建立http的連接進行多次的http的request和response(請求和響應) " , 大家想想 , 如果我們需要做一個搶購和秒殺 , 是不是需要對單個搶購和秒殺限制連接單個IP同時只能存在一個或者多個連接的限制?不然人家寫個腳本程序運行在十台八台的機器上瘋狂的請求怎么辦?當然這只是一個比較簡單的應用場景 , 更多的還是需要自己思考與摸索.


請求限制

ngx_http_limit_req_module模塊用於限制請求的處理速率,特別是單一的IP地址的請求的處理速率。使用“漏桶”方法進行限制。

配置示例

http {

...

#$binary_remote_addr表示的是客戶端的地址,zone=req_zone:1m代表的是開辟了一個名為req_zone的1M的空間,1M的空間可以存儲多少個$binary_remote_addr這里不解釋了 , Nginx官網文檔介紹的相當清除 , 速率rate=1r/s代表的是每秒1個 , 所以這里定義的配置代表:對於同一ip的請求,限制平均速率為1個請求/秒。

limit_req_zone $binary_remote_addr zone=req_zone:1m rate=1r/s;

server {

​ ...

​ location / {

​ root /usr/share/nginx/html;

​ index index.html index.htm;

​ #請求限制 : 對於符合名為req_zone的limit_req_zone 配置(對於同一ip的請求,限制平均速率為1個請求/秒) , 超過部分進行延遲處理,若超過3個請求/秒,丟棄超過部分。

​ #limit_req zone=req_zone burst=3 nodelay;

​ #請求限制 : 對於符合名為req_zone的limit_req_zone 配置 ,超過部分進行延遲處理,若超過3個請求/秒,所有請求都被過度延遲,直到名為req_zone的limit_req_zone 配置設置的1M存儲區被占滿,如果存儲區耗盡,則刪除最近最少使用的狀態。即使在此之后無法創建新狀態,請求也會因錯誤而終止。

​ #limit_req zone=req_zone burst=3;

​ #請求限制 : 對於符合名為req_zone的limit_req_zone 配置(對於同一ip的請求,限制平均速率為1個請求/秒) 若超過1個請求/秒,所有請求都被過度延遲,直到名為req_zone的limit_req_zone 配置設置的1M存儲區被占滿,如果存儲區耗盡,則刪除最近最少使用的狀態。即使在此之后無法創建新狀態,請求也會因錯誤而終止。

​ #limit_req zone=req_zone;

​ }

基本指令

limit_req_zone

語法:limit_req_zone key zone=name:size rate=rate;

只能在http塊中使用

此指令用於聲明請求限制zonezone可以保存各種key的狀態,namezone的唯一標識,size代表zone的內存大小,rate指定速率限制。

參數詳解:

1.key

若客戶的請求匹配了key,則進入zone。可以是文本、變量,通常為Nginx變量。

$binary_remote_addr(客戶的ip),$uri(不帶參數的請求地址)$request_uri(帶參數的請求地址)$server_name(服務器名稱)

支持組合使用,使用空格隔開。

2.zone

使用zone=test,指定此zone的名字為test。

3.size

在zone=name后面緊跟:size,指定此zone的內存大小。如zone=name:10m,代表name的共享內存大小為10m。通常情況下,1m可以保存16000個狀態。

4.rate

使用rate=1r/s,限制平均1秒不超過1個請求。使用rate=1r/m,限制平均1分鍾不超過1個請求。

例子:

limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;

limit_req_zone $binary_remote_addr $uri zone=two:10m rate=1r/s;

同一ip不同請求地址,進入名為one的zone,限制速率為5請求/秒

同一ip同一請求地址,進入名為two的zone,限制速率為1請求/秒

limit_req zone

語法:limit_req zone=name [burst=number] [nodelay];

可在http, server, location塊中使用

此指令用於設置共享的內存zone和最大的突發請求大小。

若請求速率超過了limit_req_zone中指定的rate但小於limit_req中的burst,則進行延遲處理,若再超過burst,就可以通過設置nodelay對其進行丟棄處理。

參數詳解:

1.zone

使用zone=name指定使用名為namezone,這個zone之前使用limit_req_zone聲明過。

2.burst(可選)

burst用於指定最大突發請求數。許多場景下,單一地限制rate並不能滿足需求,設置burst,可以延遲處理超過rate限制的請求。

3.nodelay(可選)

如果設置了nodelay,在突發請求數大於burst時,會丟棄掉這部分請求。因為如果只是延遲處理,就像”漏斗“,一旦上面加得快(請求),下面漏的慢(處理速度),”漏斗“總會有溢出的時候。這時,丟棄掉溢出的部分就顯得很有意義了。

單客戶分為三種情況:

請求速率 < rate(1r/s),正常處理

rate(1r/s) < 請求速率 < burst(5r/s),大於rate部分延遲

burst(5r/s) < 請求速率,大於burst部分丟棄(返回503服務暫時不可用)


做個演示:

未開啟請求限制時做個壓力測試

ab -n 100000 -c 1000 http://192.168.58.100/index.html

Complete requests: 10000

Failed requests: 0

這里模擬了10萬個請求 , 1000個並發 , 全部請求成功! 想想一下 , 如果我們是一個商城程序的API接口 , 正常情況下,同一個IP下10萬個請求算不算惡意攻擊?那么就需要做一下請求限制了噻 , 具體怎么限制根絕具體的邏輯去處理 , 我們這里簡單的限制一下:

同一ip請求,進入名為req_zone的zone,限制速率為20次請求/秒,

超過部分進行延遲處理,若超過10個請求/秒,丟棄超過部分。

http {

limit_req_zone $binary_remote_addr zone=req_zone:1m rate=20r/s;

server {

​ ...

​ location / {

​ ...

​ #limit_req zone=req_zone burst=10 nodelay;

​ }

修改了配置之后平滑重啟一下nginx -s reload , 再次使用之前的參數做個壓力測試看看

同一IP發起了請求10萬次, nginx只接受處理了100次,是不是nginx的壓力一下子就小了

Complete requests: 100000

Failed requests: 99900


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM