ngx_http_limit_conn_module
模塊
使用此模塊主要用來限制每秒請求數量,至於依據什麼條件限制是由我們來自定義的。
官方文檔 Module ngx_http_limit_req_module
中文翻譯的 nginx限制請求數ngx_http_limit_req_module模塊
文檔講的很詳細了,大致說下:
limit_req_zone $variable zone=name:size rate=rate;
命令的意思是,以$variable
變量為條件,起名為name
,設置的存儲空間大小為size
,設置限定頻率為rate
;
我們可以設置**多個,不同條件,不同名稱,不同大小的限制**。
這個定義我們是需要寫在**http
配置段中**。
在匹配的location中寫上limit_req zone=name [burst=number] [nodelay];
這裡burst
就是允許的漏桶數,當請求頻率大於rate
但是超出的數量不大於burst
設置的數量,則nginx會將超出的請求延遲後面返回。如果請求數量超出burst
了,則將超出部分直接返回錯誤碼,默認503
。至於nodelay
就是設置是否要延遲,有它不超過burst
的請求才延遲。
網上大多條件都是$binary_remote_addr
,其實我們可以根據自己的需求,來定義自身的相應條件,活學活用嘛,下面會有實例。
—
ngx_http_limit_conn_module
模塊
這個模塊主要限制單獨ip同一時間的連接數
官方文檔 Module ngx_http_limit_conn_module。
中文翻譯的 nginx限制連接數ngx_http_limit_conn_module模塊。
各位看文檔吧,我的實戰中沒有使用此模塊。
好了,下面進入實戰階段:
首先我們的初始配置文件時是(不完整):
http { server { listen 8080 default_server; server_name localhost:8080; location ~ .* { proxy_pass http://127.0.0.1:8080; proxy_set_header X-Real-IP $remote_addr; } } }我們的需求是,有一批接口被頻繁的不合法訪問,我們要做限制。
http { limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s; server { listen 8080 default_server; server_name localhost:8080; location ~ .* { proxy_pass http://127.0.0.1:8080; proxy_set_header X-Real-IP $remote_addr; } location ^~ /interface { limit_req zone=one burst=5 nodelay; proxy_pass http://127.0.0.1:8080; } } }
這裡加了
proxy_pass http://127.0.0.1:8080;
這裡配置了轉發,否則匹配之後會找不到服務器的。
但是這樣會有個問題,目前我們是以ip做的限制,但是有可能網吧或者校內出口就是一個或幾個ip,我們這樣限制的話會把正常用戶也限制到了,得不償失。其實我們可以換一種思路來定位到單一用戶,正常一個請求過來,我們都會設置攜帶一個關於用戶的`token`信息。至於這個`token`是如何生成的,只有服務器知道,那我們加入我們的每次請求中,`header`中帶有這個信息,`token`值,如果一個非法的請求可能沒有這個值,即使有這個值我們也可以以`token`為條件來限制,這樣更合理些。
第二版
http { limit_req_zone $http_token zone=two:10m rate=1r/s; server { listen 8080 default_server; server_name localhost:8080; location ~ .* { proxy_pass http://127.0.0.1:8080; proxy_set_header X-Real-IP $remote_addr; } location ^~ /interface { if($http_token=""){ return 403; } limit_req zone=two burst=5 nodelay; proxy_pass http://127.0.0.1:8080; } } }
在nginx
中,使用$http_變量名
,取的就是header
中相應的變量。
前方預警:我特意在這個配置中留了個坑,如果你像我這樣配置的話,重啟會報一個異常
nginx: [emerg] unknown directive "if($http_token"
,很奇怪是不,這個異常我花了很長時間才解決,原因是if
和(
中間需要個**空格**,沒錯,就是這個空格花了我好幾個小時,血淚的教訓啊,希望各位不要再重蹈覆轍。
這個問題的解決的文章:Nginx unknown directive “if($domain”
這次的配置,多少可以限制住的,對我一個nginx的小白來說,調研一點用一點,也是不錯的。