中文字幕无码系列专区|92国产精品午夜福利|久久久综合九色综合88|国产天天看免费无码在线|国产精品黄国产在线综合网|韩国三级在线视频一区二区|伊人久久大香线蕉AV网址|国产精品美女一区二区三区不卡污

北京數(shù)據(jù)家科技股份有限公司-數(shù)據(jù)家,idc官網(wǎng),算力,裸金屬,高電機(jī)房,邊緣算力,云網(wǎng)合一,北京機(jī)房 北京數(shù)據(jù)家科技股份有限公司-數(shù)據(jù)家,idc官網(wǎng),算力,裸金屬,高電機(jī)房,邊緣算力,云網(wǎng)合一,北京機(jī)房

新聞中心

數(shù)據(jù)家,idc官網(wǎng),算力,裸金屬,高電機(jī)房,邊緣算力,云網(wǎng)合一,北京機(jī)房,北京云計(jì)算,北京邊緣計(jì)算,北京裸金屬服務(wù)器,北京數(shù)據(jù)服務(wù)器,北京GPU服務(wù)器,高算力服務(wù)器,數(shù)據(jù)機(jī)房相關(guān)技術(shù)新聞最新報(bào)道

精通Nginx配置,實(shí)現(xiàn)高效精準(zhǔn)的流量限制策略

2024-02-26 14:24:49

1、概述

限流(Rate Limitting)是服務(wù)降級(jí)的一種方式,通過(guò)限制系統(tǒng)的輸入和輸出流量以達(dá)到保護(hù)系統(tǒng)的目的。

比如我們的網(wǎng)站暴露在公網(wǎng)環(huán)境中,除了用戶(hù)的正常訪問(wèn),網(wǎng)絡(luò)爬蟲(chóng)、惡意攻擊或者大促等突發(fā)流量都可能都會(huì)對(duì)系統(tǒng)造成壓力,如果這種壓力超出了服務(wù)器的處理能力,會(huì)造成響應(yīng)過(guò)慢甚至系統(tǒng)崩潰的問(wèn)題。

idc網(wǎng),算力,裸金屬,高電機(jī)房,邊緣算力,云網(wǎng)合一,北京機(jī)房,北京云計(jì)算,北京邊緣計(jì)算,北京裸金屬服務(wù)器,北京數(shù)據(jù)服務(wù)器,北京GPU服務(wù)器,高算力服務(wù)器,數(shù)據(jù)機(jī)房因此,當(dāng)并發(fā)請(qǐng)求數(shù)過(guò)大時(shí),我們通過(guò)限制一部分請(qǐng)求(比如限制同一IP的頻繁請(qǐng)求)來(lái)保證服務(wù)器可以正確響應(yīng)另一部分的請(qǐng)求。

nginx 提供了兩種限流方式,一種是限制請(qǐng)求速率,一種是限制連接數(shù)量。

另外還提供了對(duì)下載/上傳速度的限制。

2、限制請(qǐng)求速率

nginx 的 ngx_http_limit_req_module 模塊提供限制請(qǐng)求處理速率的能力,使用了漏桶算法(leaky bucket algorithm)。我們可以想像有一只上面進(jìn)水、下面勻速出水的桶,如果桶里面有水,那剛進(jìn)去的水就要存在桶里等下面的水流完之后才會(huì)流出,如果進(jìn)水的速度大于水流出的速度,桶里的水就會(huì)滿,這時(shí)水就不會(huì)進(jìn)到桶里,而是直接從桶的上面溢出。

對(duì)應(yīng)到處理網(wǎng)絡(luò)請(qǐng)求,水代表從客戶(hù)端來(lái)的請(qǐng)求,而桶代表一個(gè)隊(duì)列,請(qǐng)求在該隊(duì)列中依據(jù)先進(jìn)先出(FIFO)算法等待被處理。漏的水代表請(qǐng)求離開(kāi)緩沖區(qū)并被服務(wù)器處理,溢出代表了請(qǐng)求被丟棄并且永不被服務(wù)。

圖片圖片

2.1、正常限流

nginx 中有兩個(gè)主要的指令可以用來(lái)配置限流:limit_req_zone?和?limit_req。

下面是一個(gè)最簡(jiǎn)單的限流的例子:

limit_req_zone $binary_remote_addr znotallow=test:10m rate=2r/s;

server {
    location / {
        limit_req znotallow=test;
    }
}

imit_req_zone 用于設(shè)置限流和共享內(nèi)存區(qū)域的參數(shù),格式為:limit_req_zone key zone rate。

  • key:?定義限流對(duì)象,$binary_remote_addr?是 nginx 中的變量,表示基于?remote_addr(客戶(hù)端IP) 來(lái)做限流,binary_?是二進(jìn)制存儲(chǔ)。使用?$binary_remote_addr?而不是?$remote_addr?是因?yàn)槎M(jìn)制存儲(chǔ)可以壓縮內(nèi)存占用量。$remote_addr?變量的大小從7到15個(gè)字節(jié)不等,而?$binary_remote_addr變量的大小對(duì)于 IPv4 始終為4個(gè)字節(jié),對(duì)于 IPv6 地址則為16個(gè)字節(jié)。
  • zone:?定義共享內(nèi)存區(qū)來(lái)存儲(chǔ)訪問(wèn)信息,訪問(wèn)信息包括每個(gè) IP 地址狀態(tài)和訪問(wèn)受限請(qǐng)求 URL 的頻率等。zone 的定義又分為兩個(gè)部分:由 znotallow= 關(guān)鍵字標(biāo)識(shí)的區(qū)域名稱(chēng),以及冒號(hào)后面的區(qū)域大小。test:10m 表示一個(gè)大小為10M,名字為 test 的內(nèi)存區(qū)域。1M 能存儲(chǔ)16000個(gè) IP 地址的訪問(wèn)信息,test 大概可以存儲(chǔ)約160000個(gè)地址。nginx 創(chuàng)建新記錄的時(shí)候,會(huì)移除前60秒內(nèi)沒(méi)有被使用的記錄,如果釋放的空間還是存儲(chǔ)不了新的記錄,會(huì)返回503的狀態(tài)碼。
  • rate:?設(shè)置最大的訪問(wèn)速率。rate=2r/s(為了好模擬,rate 設(shè)置的值比較?。硎久棵胱疃嗵幚?2個(gè)請(qǐng)求。事實(shí)上 nginx 是以毫秒為粒度追蹤請(qǐng)求的,rate=2r/s?實(shí)際上是每500毫秒1個(gè)請(qǐng)求,也就是說(shuō),上一個(gè)請(qǐng)求完成后,如果500毫秒內(nèi)還有請(qǐng)求到達(dá),這些請(qǐng)求會(huì)被拒絕(默認(rèn)返回503,如果想修改返回值,可以設(shè)置limit_req_status)。

limit_req_zone?只是設(shè)置限流參數(shù),如果要生效的話,必須和?limit_req?配合使用。limit_req?的格式為:limit_req znotallow=name [burst=number] [nodelay]。

上面的例子只簡(jiǎn)單指定了?znotallow=test,表示使用 test 這個(gè)區(qū)域的配置,在請(qǐng)求 html 文件時(shí)進(jìn)行限流。我們可以理解為這個(gè)桶目前沒(méi)有任何儲(chǔ)存水滴的能力,到達(dá)的所有不能立即漏出的請(qǐng)求都會(huì)被拒絕。如果我1秒內(nèi)發(fā)送了10次請(qǐng)求,其中前500毫秒1次,后500毫秒9次,那么只有前500毫秒的請(qǐng)求和后500毫秒的第一次請(qǐng)求會(huì)響應(yīng),其余請(qǐng)求都會(huì)被拒絕。

圖片圖片

2.2、處理突發(fā)流量

上面的配置保證了 nginx 以固定的速度提供服務(wù)(2r/s),但是這種情況不適用于有突發(fā)流量的情況,我們希望可以盡可能的緩存請(qǐng)求并處理它們,此時(shí)需要在?limit_req?上增加 burst 參數(shù):

limit_req_zone $binary_remote_addr znotallow=test:10m rate=2r/s;

server {
    location / {
        limit_req znotallow=test burst=5;
    }
}

burst 表示在超過(guò)設(shè)定的訪問(wèn)速率后能額外處理的請(qǐng)求數(shù)。當(dāng)?rate=2r/s?時(shí),表示每500ms 可以處理一個(gè)請(qǐng)求。burst=5時(shí),如果同時(shí)有10個(gè)請(qǐng)求到達(dá),nginx 會(huì)處理第1個(gè)請(qǐng)求,剩余9個(gè)請(qǐng)求中,會(huì)有5個(gè)被放入隊(duì)列,剩余的4個(gè)請(qǐng)求會(huì)直接被拒絕。然后每隔500ms從隊(duì)列中獲取一個(gè)請(qǐng)求進(jìn)行處理,此時(shí)如果后面繼續(xù)有請(qǐng)求進(jìn)來(lái),如果隊(duì)列中的請(qǐng)求數(shù)目超過(guò)了5,會(huì)被拒絕,不足5的時(shí)候會(huì)添加到隊(duì)列中進(jìn)行等待。我們可以理解為現(xiàn)在的桶可以存5滴水:

圖片圖片

配置 burst 之后,雖然同時(shí)到達(dá)的請(qǐng)求不會(huì)全部被拒絕,但是仍需要等待500ms 一次的處理時(shí)間,放入桶中的第5個(gè)請(qǐng)求需要等待500ms * 4的時(shí)間才能被處理,更長(zhǎng)的等待時(shí)間意味著用戶(hù)的流失,在許多場(chǎng)景下,這個(gè)等待時(shí)間是不可接受的。此時(shí)我們需要增加 nodelay 參數(shù),和 burst 配合使用。

limit_req_zone $binary_remote_addr znotallow=test:10m rate=2r/s;

server {
    location / {
        limit_req znotallow=test burst=5 nodelay;
    }
}

nodelay 表示不延遲。設(shè)置 nodelay 后,第一個(gè)到達(dá)的請(qǐng)求和隊(duì)列中的請(qǐng)求會(huì)立即進(jìn)行處理,不會(huì)出現(xiàn)等待的請(qǐng)求。

圖片圖片

需要注意的是,雖然隊(duì)列中的5個(gè)請(qǐng)求立即被處理了,但是隊(duì)列中的位置依舊是按照500ms 的速度依次被釋放的。后面的4個(gè)請(qǐng)求依舊是被拒絕的,長(zhǎng)期來(lái)看并不會(huì)提高吞吐量的上限,長(zhǎng)期吞吐量的上限是由設(shè)置的 rate 決定的

2.3、設(shè)置白名單

如果遇到不需要限流的情況,比如測(cè)試要壓測(cè),可以通過(guò)配置白名單,取消限流的設(shè)置。白名單要用到 nginx 的?ngx_http_geo_module?和?ngx_http_map_module?模塊。

geo $limit {
    default 1;
    10.0.0.0/8 0;
    192.168.0.0/24 0;
}

map $limit $limit_key {
    0 "";
    1 $binary_remote_addr;
}

limit_req_zone $limit_key znotallow=mylimit:10m rate=2r/s;

geo 指令可以根據(jù) IP 創(chuàng)建變量?$limit。$limit?的默認(rèn)值是1,如果匹配到了下面的 IP,則返回對(duì)應(yīng)的值(這里返回的是0)。

之后通過(guò) map 指令,將?$limit?的值映射為$limit_key:在白名單內(nèi)的,$limit_key?為空字符串,不在白名單內(nèi)的,則為?$binary_remote_addr。當(dāng)limit_req_zone指令的第一個(gè)參數(shù)是一個(gè)空字符串,限制不起作用,因此白名單的 IP 地址(在10.0.0.0/8和192.168.0.0/24子網(wǎng)中)沒(méi)有被限制,其它 IP 地址都被限制為 2r/s

2.4、limit_req重復(fù)

如果同一個(gè) location 下配置了多條?limit_req?的指令,這些指令所定義的限制都會(huì)被使用。

geo $limit {
    default 1;
    10.0.0.0/8 0;
    192.168.0.0/24 0;
}

map $limit $limit_key {
    0 "";
    1 $binary_remote_addr;
}

limit_req_zone $limit_key znotallow=mylimit:10m rate=2r/s;
limit_req_zone $binary_remote_addr znotallow=myLimit2:10m rate=10r/s;
server {
    location ~* .(html)$ {
        limit_req znotallow=mylimit burst=5 nodelay;
        limit_req znotallow=myLimit2 burst=5 nodelay;
    }
}

上面的例子配置了兩條規(guī)則,myLimit 和 myLimit2。白名單用戶(hù)雖然沒(méi)有匹配到mylimit的規(guī)則,但是根據(jù)規(guī)則 mylimit2,被限制為10r/s。對(duì)于不在白名單的用戶(hù),則需要同時(shí)匹配mylimit 和 mylimit2,兩者中最嚴(yán)格的條件 2r/s 會(huì)起作用。

3、限制連接數(shù)

nginx 的?ngx_http_limit_conn_module?模塊提供限制連接數(shù)的能力,包含兩個(gè)指令limit_conn_zone?和?limit_conn,格式為limit_conn_zone key zone。

limit_conn_zone $binary_remote_addr znotallow=perip:10m;
limit_conn_zone $server_name znotallow=perserver:10m;
server {
    location ~* .(html)$ {
        limit_conn perip 10;
        limit_conn perserver 100;
    }
}
  • limit_conn perip 10:?key 是$binary_remote_addr,表示限制單個(gè)IP同時(shí)最多能持有10個(gè)連接。
  • limit_conn perserver 100:?key 是?$server_name,表示虛擬主機(jī)(server) 同時(shí)能處理并發(fā)連接的總數(shù)為100。

需要注意的是:只有當(dāng) request header 被后端server處理后,這個(gè)連接才進(jìn)行計(jì)數(shù)。

4、上傳/下載速率限制

limit_rate主要用于限制用戶(hù)和服務(wù)器之間傳輸?shù)淖止?jié)數(shù),最常用的場(chǎng)景可能就是下載/上傳限速。limit_rate并沒(méi)有單獨(dú)的一個(gè)模塊,而是在ngx_http_core_module中,同時(shí)它的相關(guān)指令也比較少,只有l(wèi)imit_rate和limit_rate_after這兩個(gè)指令。

4.1、limit_rate

server {
    location / {
        limit_rate 4k;
    }
}
  • limit_rate的用法非常簡(jiǎn)單,后面跟隨的rate就是具體限速的閾值
  • 注意默認(rèn)的單位是bytes/s,也就是每秒傳輸?shù)淖止?jié)數(shù)Bytes而不是比特?cái)?shù)bits
  • rate可以設(shè)置為變量,從而可以實(shí)現(xiàn)動(dòng)態(tài)限速
  • 限速指令的生效范圍是根據(jù)每個(gè)連接確定的,例如上面限定每個(gè)連接的速率為4k,也就是當(dāng)客戶(hù)端發(fā)起兩個(gè)連接的時(shí)候,速率就可以變?yōu)?k

4.2、limit_rate_after

server {
    location / {
     limit_rate_after 500k;
        limit_rate 4k;
    }
}

limit_rate_after允許在傳輸了一部分?jǐn)?shù)據(jù)之后再進(jìn)行限速,例如上面的配置中就是傳輸?shù)那?00k數(shù)據(jù)不限速,500k之后再進(jìn)行限速。比較常見(jiàn)的應(yīng)用場(chǎng)景如分段下載限速,超過(guò)指定大小的部分再進(jìn)行限速;又或者是流媒體視頻網(wǎng)站一般為了保證用戶(hù)體驗(yàn)而不會(huì)對(duì)第一個(gè)畫(huà)面進(jìn)行限速,確保其能夠盡快加載出來(lái),等用戶(hù)開(kāi)始觀看視頻之后,再把帶寬限制在合理的范圍內(nèi),從而降低因客戶(hù)端網(wǎng)速過(guò)快導(dǎo)致提前加載過(guò)多內(nèi)容帶來(lái)的額外成本。

4.3、proxy_limit_rate

proxy_limit_rate的基本原理和用法與limit_rate幾乎一樣,唯一不同的是proxy_limit_rate是限制nginx和后端upstream服務(wù)器之間的連接速率而limit_rate限制的是nginx和客戶(hù)端之間的連接速率。需要注意的是proxy_limit_rate需要開(kāi)啟了proxy_buffering這個(gè)指令才會(huì)生效。

#語(yǔ)法:
Syntax: proxy_limit_rate rate;
Default:    proxy_limit_rate 0;
Context:    http, server, location
This directive appeared in version 1.7.7.

4.4、動(dòng)態(tài)限速

limit_rate的一大特點(diǎn)就是能夠使用變量,這就意味著和map指令之類(lèi)的進(jìn)行組合就可以實(shí)現(xiàn)動(dòng)態(tài)限速功能,這里只列幾個(gè)簡(jiǎn)單的示范

4.4.1、基于時(shí)間動(dòng)態(tài)限速

這里引入了nginx內(nèi)置的一個(gè)ssi模塊,這個(gè)模塊有兩個(gè)比較有意思的時(shí)間變量:$date_local$date_gmt,分別對(duì)應(yīng)當(dāng)前時(shí)間和GMT時(shí)間

這里使用變量和map指令組合的方式,利用正則表達(dá)式匹配不同的時(shí)間段,再結(jié)合map變量將不同時(shí)間段和不同的限速對(duì)應(yīng)起來(lái)。

map $date_local $limit_rate_time {
     default 4K;
     ~(00:|01:|02:|03:|04:|05:|06:|07:).*:.* 16K;
     ~(08:|12:|13:|18:).*:.* 8K;
     ~(19:|20:|21:|22:|23:).*:.* 16K;
 }
 
 limit_rate $limit_rate_time

4.2、基于變量動(dòng)態(tài)限速

有些服務(wù)可能會(huì)對(duì)不用的用戶(hù)進(jìn)行不同的限速,例如VIP用戶(hù)的速度要更快一些等,例如下面可以針對(duì)不同的cookie進(jìn)行限速

map $cookie_User $limit_rate_cookie {
     gold 64K;
     silver 32K;
     copper 16K;
     iron 8K;
 }
 
 limit_rate $limit_rate_cookie