nginx實現ip限流的具體示例
說到限流,大家一定能想到很多算法,比如 令牌桶 、漏桶 、計數器限流、 信號量 等等。 解決方案也有很多,以 java 為例,Guava 庫中的 RateLimiter 類 可以實現,Semaphore 類也可以實現。再復雜點兒,比如你是一個分布式微服務系統(tǒng),可以上 Hystrix、Resilience4j 這種現成的方案。
從系統(tǒng)架構上來說,無非是在單體應用的當前進程中實現,還是分布式應用的非當前進程中之實現。當然還有另一種方案,就是不在業(yè)務應用中實現,而是把這種跟業(yè)務不那么緊耦合的功能抽象出去,在網絡層面對所有進入系統(tǒng)的請求進行統(tǒng)一的限流控制,這種方式的好處是可以避免每個微服務都實現自己的限流邏輯。
現在很多 API 網關,尤其是新晉的 “云原生” 網關都具備這個功能(基本是標配),比如:Zuul、Kong、Ambassador、APISIX 等。
我們先不論系統(tǒng)是不是分布式微服務的,就單說限流這個事兒,其實也完全可以用 API 網關的思路來實現。就是我不用非要把代碼寫在應用中,如果我就是不想改代碼呢?我想隨時調整個限流策略還得重啟應用? 應用那么重,生效時間那么長,我可不想重啟!
所以我們回頭看看自己架構中的這些軟件,一定能想到這位老朋友 Nginx 。當然無論是原味的 Nginx 還是跟它有血緣關系的 openResty 都一樣。
想像一下,用 nginx 配置一下然后nginx -s reload 就能搞定了,豈不痛快 ?!
正題
下文我們開始介紹在 nginx 怎么配置能實現針對某些(討厭的)ip 進行限流,且不影響系統(tǒng)正常運行。 (感嘆:nginx 是個好東西?。。。?/p>
可能有些朋友看到標題就已經開始寫 prompt 了,喝著 coffee 等著 AI 給你一行行輸出答案,然后心里想:“什么年代了,大哥,還用寫個文章專門說這事兒嗎?你得學會用工具呀” 。
我想說的是,關于這個問題 AI 能給你回答對 90% 的內容,剩下的 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 地址與地理位置之間的映射需要額外的數據庫或服務來提供。許多第三方服務和數據庫(如 MaxMind GeoIP、GeoLite2 等)可以用來更精確地將 IP 地址轉換為地理位置信息。
解釋一下我們上文中中 geo 的配置:
- geo $limit_ip { ... }:定義了一個名為 $limit_ip的變量,用于根據客戶端 IP 地址設置不同的值。
- default 0;:默認情況下,如果客戶端 IP 地址不在列表中,$limit_ip 的值為 0。
- 1.2.3.4 1;:如果客戶端 IP 地址是 1.2.3.4,則 $limit_ip 的值為 1。這里的 1 是一個標記,表示這個 IP 地址需要被限制。
總結來說就是用 geo 指令標記需要限制的 IP 地址
map 指令:
- map $limit_ip $limit_key { ... }:根據$limit_ip的值來設置另一個變量$limit_key。
- 0 "";:如果$limit_ip的值為 0(即默認情況),則$limit_key的值為空字符串。
- 1 $binary_remote_addr;:如果$limit_ip的值為 1(即被標記的 IP 地址),則$limit_key的值為客戶端 IP 地址的二進制形式($binary_remote_addr)。
不知道聰明的你看出來沒有,我們這里其實設置的是 “黑名單” (即我想限制哪些 ip 我就配置哪些,剩下的不限制),在 geo 配置的 ip 到了 map 這里以后,將這些 IP 地址映射到了一個變量上,即 limit_key 。如果你想設置白名單(即我想讓哪些 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:設置共享內存區(qū)域的大小為 10MB,用于存儲限流信息。
- rate=2r/s:設置每個鍵值(即每個 IP 地址)的請求速率限制為每秒 2 個請求。
其實這些指令都有一些詳細參數,簡單起見,我就不介紹了,都有 AI 了,需要的話自己查吧。我們說點兒重點。
我猜你可能關心 zone=mylimit 里面到底是什么樣的,里面到底有啥 。是的,這很重要,了解清楚 zone 的結構很關鍵,關于 zone 的數據我沒細看過,但結構大致類似這樣:
{
"mylimit": {
"123.124.210.242": {
"current": 0, // 當前請求計數
"last": 1618305483, // 上次請求的時間戳
"tokens": 2, // 當前令牌桶中的令牌數
"delay": 0 // 由于限流導致的延遲(秒)
},
// ... 其他被限流的 IP 地址信息
"192.168.1.100": {
"current": 1,
"last": 1618305495,
"tokens": 1,
"delay": 0
}
}
}好了,到這里我們第一部分的配置就結束了,是不很簡單? 然后我們進行第二部分的配置,也很簡單。
前文我們第一部分的配置只是定義了一個限流的策略,我們還沒應用呢呀。所以我們要在需要的地方把它用起來。
很簡單,在需要限流的 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 ...
到此這篇關于nginx實現ip限流的具體示例的文章就介紹到這了,更多相關nginx ip限流內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Nginx?403?forbidden錯誤的原因以及解決方法
yum安裝nginx,安裝一切正常,但是訪問時報403 forbidden,下面這篇文章主要給大家介紹了關于Nginx?403?forbidden錯誤的原因以及解決方法,需要的朋友可以參考下2022-08-08

