nginx實現(xiàn)ip限流的具體示例
說到限流,大家一定能想到很多算法,比如 令牌桶 、漏桶 、計數(shù)器限流、 信號量 等等。 解決方案也有很多,以 java 為例,Guava 庫中的 RateLimiter 類 可以實現(xiàn),Semaphore 類也可以實現(xiàn)。再復雜點兒,比如你是一個分布式微服務(wù)系統(tǒng),可以上 Hystrix、Resilience4j 這種現(xiàn)成的方案。
從系統(tǒng)架構(gòu)上來說,無非是在單體應(yīng)用的當前進程中實現(xiàn),還是分布式應(yīng)用的非當前進程中之實現(xiàn)。當然還有另一種方案,就是不在業(yè)務(wù)應(yīng)用中實現(xiàn),而是把這種跟業(yè)務(wù)不那么緊耦合的功能抽象出去,在網(wǎng)絡(luò)層面對所有進入系統(tǒng)的請求進行統(tǒng)一的限流控制,這種方式的好處是可以避免每個微服務(wù)都實現(xiàn)自己的限流邏輯。
現(xiàn)在很多 API 網(wǎng)關(guān),尤其是新晉的 “云原生” 網(wǎng)關(guān)都具備這個功能(基本是標配),比如:Zuul、Kong、Ambassador、APISIX 等。
我們先不論系統(tǒng)是不是分布式微服務(wù)的,就單說限流這個事兒,其實也完全可以用 API 網(wǎng)關(guān)的思路來實現(xiàn)。就是我不用非要把代碼寫在應(yīng)用中,如果我就是不想改代碼呢?我想隨時調(diào)整個限流策略還得重啟應(yīng)用? 應(yīng)用那么重,生效時間那么長,我可不想重啟!
所以我們回頭看看自己架構(gòu)中的這些軟件,一定能想到這位老朋友 Nginx 。當然無論是原味的 Nginx 還是跟它有血緣關(guān)系的 openResty 都一樣。
想像一下,用 nginx 配置一下然后nginx -s reload 就能搞定了,豈不痛快 ?!
正題
下文我們開始介紹在 nginx 怎么配置能實現(xiàn)針對某些(討厭的)ip 進行限流,且不影響系統(tǒng)正常運行。 (感嘆:nginx 是個好東西?。。。?/p>
可能有些朋友看到標題就已經(jīng)開始寫 prompt 了,喝著 coffee 等著 AI 給你一行行輸出答案,然后心里想:“什么年代了,大哥,還用寫個文章專門說這事兒嗎?你得學會用工具呀” 。
我想說的是,關(guān)于這個問題 AI 能給你回答對 90% 的內(nèi)容,剩下的 10% 你得自己改。開發(fā)同學都知道 ,別說 10% 了,0.1% 不對,程序也不 work 呀。我是不會告訴你我花了一下午時間跟 AI 都聊了什么的。
你也別抬杠說我用的工具不對,市面上但凡有的我都用了,真不行,所以我覺得還是值得寫一下的。
配置詳解
其實改的地方不多,首先我們要在 nginx 默認配置文件的 http 下面配置:
geo $limit_ip {
default 0; # 默認為 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 名字來源于“geographic”,意指地理位置。但是值得注意的是,geo 指令實際上只基于 IP 地址進行匹配,而 IP 地址與地理位置之間的映射需要額外的數(shù)據(jù)庫或服務(wù)來提供。許多第三方服務(wù)和數(shù)據(jù)庫(如 MaxMind GeoIP、GeoLite2 等)可以用來更精確地將 IP 地址轉(zhuǎn)換為地理位置信息。
解釋一下我們上文中中 geo 的配置:
- geo $limit_ip { ... }:定義了一個名為 $limit_ip的變量,用于根據(jù)客戶端 IP 地址設(shè)置不同的值。
- default 0;:默認情況下,如果客戶端 IP 地址不在列表中,$limit_ip 的值為 0。
- 1.2.3.4 1;:如果客戶端 IP 地址是 1.2.3.4,則 $limit_ip 的值為 1。這里的 1 是一個標記,表示這個 IP 地址需要被限制。
總結(jié)來說就是用 geo 指令標記需要限制的 IP 地址
map 指令:
- map $limit_ip $limit_key { ... }:根據(jù)$limit_ip的值來設(shè)置另一個變量$limit_key。
- 0 "";:如果$limit_ip的值為 0(即默認情況),則$limit_key的值為空字符串。
- 1 $binary_remote_addr;:如果$limit_ip的值為 1(即被標記的 IP 地址),則$limit_key的值為客戶端 IP 地址的二進制形式($binary_remote_addr)。
不知道聰明的你看出來沒有,我們這里其實設(shè)置的是 “黑名單” (即我想限制哪些 ip 我就配置哪些,剩下的不限制),在 geo 配置的 ip 到了 map 這里以后,將這些 IP 地址映射到了一個變量上,即 limit_key 。如果你想設(shè)置白名單(即我想讓哪些 ip 不被限制我就配置哪些,剩下的都限制)不就是反過來操作嘛。
舉個白名單的例子:
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 指令定義了一個限流區(qū)域,對標記的 IP 地址進行請求速率限制。如果一個 IP 地址不在 geo 指令中定義,則不受限制。如果一個 IP 地址被標記,則它的請求速率會被限制在每秒 2 個請求。
- $limit_key:使用$limit_key 變量作為限流的鍵。
- zone=mylimit:10m:設(shè)置共享內(nèi)存區(qū)域的大小為 10MB,用于存儲限流信息。
- rate=2r/s:設(shè)置每個鍵值(即每個 IP 地址)的請求速率限制為每秒 2 個請求。
其實這些指令都有一些詳細參數(shù),簡單起見,我就不介紹了,都有 AI 了,需要的話自己查吧。我們說點兒重點。
我猜你可能關(guān)心 zone=mylimit 里面到底是什么樣的,里面到底有啥 。是的,這很重要,了解清楚 zone 的結(jié)構(gòu)很關(guān)鍵,關(guān)于 zone 的數(shù)據(jù)我沒細看過,但結(jié)構(gòu)大致類似這樣:
{
"mylimit": {
"123.124.210.242": {
"current": 0, // 當前請求計數(shù)
"last": 1618305483, // 上次請求的時間戳
"tokens": 2, // 當前令牌桶中的令牌數(shù)
"delay": 0 // 由于限流導致的延遲(秒)
},
// ... 其他被限流的 IP 地址信息
"192.168.1.100": {
"current": 1,
"last": 1618305495,
"tokens": 1,
"delay": 0
}
}
}好了,到這里我們第一部分的配置就結(jié)束了,是不很簡單? 然后我們進行第二部分的配置,也很簡單。
前文我們第一部分的配置只是定義了一個限流的策略,我們還沒應(yīng)用呢呀。所以我們要在需要的地方把它用起來。
很簡單,在需要限流的 location 中這樣寫:
location /abc/api {
limit_req zone=mylimit;
}沒了? 就一句?
對,沒了。是不很簡單?簡單到我都不想解釋,如果你理解了前文你就懂了,我就不解釋了。畢竟你會用 AI 不是。
然后你就可以重新加載配置,或重啟 nginx 了。再然后你就要耐心等待和觀察,等待之前那些討厭的惡意 ip 再次造訪,順利地話你會在 nginx 的 error 日志中看到類似這樣的信息 :
... [error] ..limiting requests,excess:0.996 by zone "mylimit", client:1.2.3.4 ...
到此這篇關(guān)于nginx實現(xiàn)ip限流的具體示例的文章就介紹到這了,更多相關(guān)nginx ip限流內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于lua_shared_dict的incr方法詳解
這篇文章主要介紹了關(guān)于lua_shared_dict的incr方法,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-06-06
Nginx(PHP/fastcgi)的PATH_INFO問題
PATH_INFO是一個CGI 1.1的標準,經(jīng)常用來做為傳參載體. 比如, 我們可以使用PATH_INFO來代替Rewrite來實現(xiàn)偽靜態(tài)頁面, 另外不少PHP框架也使用PATH_INFO來作為路由載體.2011-08-08
Nginx配置參數(shù)中文說明詳解(負載均衡與反向代理)
最近在看高性能Linux服務(wù)器構(gòu)建實戰(zhàn)的Nginx章節(jié),對其nginx介紹的非常詳細,現(xiàn)把經(jīng)常用到的Nginx配置參數(shù)中文說明摘錄和nginx做負載均衡的本人真實演示實例抄錄下來以便以后查看2020-03-03
實例詳解SpringBoot+nginx實現(xiàn)資源上傳功能
這篇文章主要介紹了SpringBoot+nginx實現(xiàn)資源上傳功能,由于小編最近在使用nginx放置靜態(tài)資源問題,遇到很多干貨,特此分享到腳本之家平臺,供大家參考,需要的朋友可以參考下2019-10-10
Dockerfile打包nginx鏡像的實現(xiàn)步驟
本文主要介紹了Dockerfile打包nginx鏡像的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-10-10

