nginx實(shí)現(xiàn)ip限流的具體示例
說(shuō)到限流,大家一定能想到很多算法,比如 令牌桶 、漏桶 、計(jì)數(shù)器限流、 信號(hào)量 等等。 解決方案也有很多,以 java 為例,Guava 庫(kù)中的 RateLimiter 類 可以實(shí)現(xiàn),Semaphore 類也可以實(shí)現(xiàn)。再?gòu)?fù)雜點(diǎn)兒,比如你是一個(gè)分布式微服務(wù)系統(tǒng),可以上 Hystrix、Resilience4j 這種現(xiàn)成的方案。
從系統(tǒng)架構(gòu)上來(lái)說(shuō),無(wú)非是在單體應(yīng)用的當(dāng)前進(jìn)程中實(shí)現(xiàn),還是分布式應(yīng)用的非當(dāng)前進(jìn)程中之實(shí)現(xiàn)。當(dāng)然還有另一種方案,就是不在業(yè)務(wù)應(yīng)用中實(shí)現(xiàn),而是把這種跟業(yè)務(wù)不那么緊耦合的功能抽象出去,在網(wǎng)絡(luò)層面對(duì)所有進(jìn)入系統(tǒng)的請(qǐng)求進(jìn)行統(tǒng)一的限流控制,這種方式的好處是可以避免每個(gè)微服務(wù)都實(shí)現(xiàn)自己的限流邏輯。
現(xiàn)在很多 API 網(wǎng)關(guān),尤其是新晉的 “云原生” 網(wǎng)關(guān)都具備這個(gè)功能(基本是標(biāo)配),比如:Zuul、Kong、Ambassador、APISIX 等。
我們先不論系統(tǒng)是不是分布式微服務(wù)的,就單說(shuō)限流這個(gè)事兒,其實(shí)也完全可以用 API 網(wǎng)關(guān)的思路來(lái)實(shí)現(xiàn)。就是我不用非要把代碼寫(xiě)在應(yīng)用中,如果我就是不想改代碼呢?我想隨時(shí)調(diào)整個(gè)限流策略還得重啟應(yīng)用? 應(yīng)用那么重,生效時(shí)間那么長(zhǎng),我可不想重啟!
所以我們回頭看看自己架構(gòu)中的這些軟件,一定能想到這位老朋友 Nginx 。當(dāng)然無(wú)論是原味的 Nginx 還是跟它有血緣關(guān)系的 openResty 都一樣。
想像一下,用 nginx 配置一下然后nginx -s reload
就能搞定了,豈不痛快 ?!
正題
下文我們開(kāi)始介紹在 nginx 怎么配置能實(shí)現(xiàn)針對(duì)某些(討厭的)ip 進(jìn)行限流,且不影響系統(tǒng)正常運(yùn)行。 (感嘆:nginx 是個(gè)好東西!?。。?/p>
可能有些朋友看到標(biāo)題就已經(jīng)開(kāi)始寫(xiě) prompt 了,喝著 coffee 等著 AI 給你一行行輸出答案,然后心里想:“什么年代了,大哥,還用寫(xiě)個(gè)文章專門(mén)說(shuō)這事兒?jiǎn)??你得學(xué)會(huì)用工具呀” 。
我想說(shuō)的是,關(guān)于這個(gè)問(wèn)題 AI 能給你回答對(duì) 90% 的內(nèi)容,剩下的 10% 你得自己改。開(kāi)發(fā)同學(xué)都知道 ,別說(shuō) 10% 了,0.1% 不對(duì),程序也不 work 呀。我是不會(huì)告訴你我花了一下午時(shí)間跟 AI 都聊了什么的。
你也別抬杠說(shuō)我用的工具不對(duì),市面上但凡有的我都用了,真不行,所以我覺(jué)得還是值得寫(xiě)一下的。
配置詳解
其實(shí)改的地方不多,首先我們要在 nginx 默認(rèn)配置文件的 http 下面配置:
geo $limit_ip { default 0; # 默認(rèn)為 0,表示不受限制 1.2.3.4 1; # 需要被限制的 IP # 添加更多需要限制的 IP 地址 } map $limit_ip $limit_key { 0 ""; 1 $binary_remote_addr; } # 定義限流區(qū)域 limit_req_zone $limit_key zone=mylimit:10m rate=2r/s;
我們解釋一下。
geo 指令:
geo 名字來(lái)源于“geographic”,意指地理位置。但是值得注意的是,geo 指令實(shí)際上只基于 IP 地址進(jìn)行匹配,而 IP 地址與地理位置之間的映射需要額外的數(shù)據(jù)庫(kù)或服務(wù)來(lái)提供。許多第三方服務(wù)和數(shù)據(jù)庫(kù)(如 MaxMind GeoIP、GeoLite2 等)可以用來(lái)更精確地將 IP 地址轉(zhuǎn)換為地理位置信息。
解釋一下我們上文中中 geo 的配置:
- geo $limit_ip { ... }:定義了一個(gè)名為 $limit_ip的變量,用于根據(jù)客戶端 IP 地址設(shè)置不同的值。
- default 0;:默認(rèn)情況下,如果客戶端 IP 地址不在列表中,$limit_ip 的值為 0。
- 1.2.3.4 1;:如果客戶端 IP 地址是 1.2.3.4,則 $limit_ip 的值為 1。這里的 1 是一個(gè)標(biāo)記,表示這個(gè) IP 地址需要被限制。
總結(jié)來(lái)說(shuō)就是用 geo 指令標(biāo)記需要限制的 IP 地址
map 指令:
- map $limit_ip $limit_key { ... }:根據(jù)$limit_ip的值來(lái)設(shè)置另一個(gè)變量$limit_key。
- 0 "";:如果$limit_ip的值為 0(即默認(rèn)情況),則$limit_key的值為空字符串。
- 1 $binary_remote_addr;:如果$limit_ip的值為 1(即被標(biāo)記的 IP 地址),則$limit_key的值為客戶端 IP 地址的二進(jìn)制形式($binary_remote_addr)。
不知道聰明的你看出來(lái)沒(méi)有,我們這里其實(shí)設(shè)置的是 “黑名單” (即我想限制哪些 ip 我就配置哪些,剩下的不限制),在 geo 配置的 ip 到了 map 這里以后,將這些 IP 地址映射到了一個(gè)變量上,即 limit_key 。如果你想設(shè)置白名單(即我想讓哪些 ip 不被限制我就配置哪些,剩下的都限制)不就是反過(guò)來(lái)操作嘛。
舉個(gè)白名單的例子:
geo $limit { default 1; 10.0.0.0/8 0; 192.168.0.0/24 0; 172.20.0.35 0; } map $limit $limit_key { 0 ""; 1 $binary_remote_addr; }
limit_req_zone
接著是整塊配置的最后一行。
limit_req_zone $limit_key zone=mylimit:10m rate=2r/s;
使用 limit_req_zone 指令定義了一個(gè)限流區(qū)域,對(duì)標(biāo)記的 IP 地址進(jìn)行請(qǐng)求速率限制。如果一個(gè) IP 地址不在 geo 指令中定義,則不受限制。如果一個(gè) IP 地址被標(biāo)記,則它的請(qǐng)求速率會(huì)被限制在每秒 2 個(gè)請(qǐng)求。
- $limit_key:使用$limit_key 變量作為限流的鍵。
- zone=mylimit:10m:設(shè)置共享內(nèi)存區(qū)域的大小為 10MB,用于存儲(chǔ)限流信息。
- rate=2r/s:設(shè)置每個(gè)鍵值(即每個(gè) IP 地址)的請(qǐng)求速率限制為每秒 2 個(gè)請(qǐng)求。
其實(shí)這些指令都有一些詳細(xì)參數(shù),簡(jiǎn)單起見(jiàn),我就不介紹了,都有 AI 了,需要的話自己查吧。我們說(shuō)點(diǎn)兒重點(diǎn)。
我猜你可能關(guān)心 zone=mylimit 里面到底是什么樣的,里面到底有啥 。是的,這很重要,了解清楚 zone 的結(jié)構(gòu)很關(guān)鍵,關(guān)于 zone 的數(shù)據(jù)我沒(méi)細(xì)看過(guò),但結(jié)構(gòu)大致類似這樣:
{ "mylimit": { "123.124.210.242": { "current": 0, // 當(dāng)前請(qǐng)求計(jì)數(shù) "last": 1618305483, // 上次請(qǐng)求的時(shí)間戳 "tokens": 2, // 當(dāng)前令牌桶中的令牌數(shù) "delay": 0 // 由于限流導(dǎo)致的延遲(秒) }, // ... 其他被限流的 IP 地址信息 "192.168.1.100": { "current": 1, "last": 1618305495, "tokens": 1, "delay": 0 } } }
好了,到這里我們第一部分的配置就結(jié)束了,是不很簡(jiǎn)單? 然后我們進(jìn)行第二部分的配置,也很簡(jiǎn)單。
前文我們第一部分的配置只是定義了一個(gè)限流的策略,我們還沒(méi)應(yīng)用呢呀。所以我們要在需要的地方把它用起來(lái)。
很簡(jiǎn)單,在需要限流的 location 中這樣寫(xiě):
location /abc/api { limit_req zone=mylimit; }
沒(méi)了? 就一句?
對(duì),沒(méi)了。是不很簡(jiǎn)單?簡(jiǎn)單到我都不想解釋,如果你理解了前文你就懂了,我就不解釋了。畢竟你會(huì)用 AI 不是。
然后你就可以重新加載配置,或重啟 nginx 了。再然后你就要耐心等待和觀察,等待之前那些討厭的惡意 ip 再次造訪,順利地話你會(huì)在 nginx 的 error 日志中看到類似這樣的信息 :
... [error] ..limiting requests,excess:0.996 by zone "mylimit", client:1.2.3.4 ...
到此這篇關(guān)于nginx實(shí)現(xiàn)ip限流的具體示例的文章就介紹到這了,更多相關(guān)nginx ip限流內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Nginx四層負(fù)載均衡的實(shí)現(xiàn)示例
Nginx?不支持傳統(tǒng)的四層負(fù)載均衡,但可以通過(guò)stream模塊配合TCP實(shí)現(xiàn)類似的功能,本文主要介紹了Nginx四層負(fù)載均衡的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2024-04-04nginx實(shí)現(xiàn)動(dòng)靜分離的方法示例
Nginx的靜態(tài)處理能力很強(qiáng),但是動(dòng)態(tài)處理能力不足,因此,在企業(yè)中常用動(dòng)靜分離技術(shù),本文就詳細(xì)的介紹一下如何使用,感興趣的可以了解一下2021-11-11Nginx靜態(tài)資源服務(wù)器的實(shí)現(xiàn)示例
靜態(tài)資源即非服務(wù)器動(dòng)態(tài)生成的文件,本文主要介紹了Nginx靜態(tài)資源服務(wù)器的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-08-08nginx部署https網(wǎng)站的實(shí)現(xiàn)步驟(親測(cè))
本文詳細(xì)介紹了使用Nginx在保持與http服務(wù)兼容的情況下部署HTTPS,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-02-02Nginx?403?forbidden錯(cuò)誤的原因以及解決方法
yum安裝nginx,安裝一切正常,但是訪問(wèn)時(shí)報(bào)403 forbidden,下面這篇文章主要給大家介紹了關(guān)于Nginx?403?forbidden錯(cuò)誤的原因以及解決方法,需要的朋友可以參考下2022-08-08Nginx動(dòng)態(tài)IP黑名單的實(shí)現(xiàn)步驟
為了封禁某些爬蟲(chóng)或者惡意用戶對(duì)服務(wù)器的請(qǐng)求,我們需要建立一個(gè)動(dòng)態(tài)的?IP?黑名單,本文主要介紹了Nginx動(dòng)態(tài)IP黑名單的實(shí)現(xiàn)步驟,具有一定的參考價(jià)值,感興趣的可以了解一下2025-02-02nginx訪問(wèn)路徑映射資源目錄的實(shí)現(xiàn)
本文主要介紹了nginx訪問(wèn)路徑映射資源目錄,Nginx映射資源目錄是指在Nginx配置文件中設(shè)定規(guī)則,使得當(dāng)客戶端向Nginx服務(wù)器發(fā)送請(qǐng)求訪問(wèn)某個(gè)URL時(shí),Nginx能夠?qū)⒃揢RL映射到服務(wù)器本地的實(shí)際文件目錄,感興趣的可以了解一下2024-06-06