Nginx 流量控制/限流的具體實(shí)現(xiàn)示例
1. Nginx 限流介紹
Nginx 限流是一種用于控制并發(fā)連接數(shù)或請求速率的機(jī)制,旨在保護(hù)服務(wù)器免受過多的請求影響,防止因請求過載而導(dǎo)致系統(tǒng)性能下降或崩潰。對 Nginx 限流的介紹可能涉及以下幾個關(guān)鍵點(diǎn):
- 什么是限流: 限流是一種流量控制手段,用于限制單位時間內(nèi)可以通過系統(tǒng)的請求數(shù)或連接數(shù)。這有助于防止系統(tǒng)超負(fù)荷運(yùn)行,保持系統(tǒng)的穩(wěn)定性和可用性。
- 為何需要限流: 在高并發(fā)的網(wǎng)絡(luò)環(huán)境中,突然涌入的大量請求可能會超出服務(wù)器的處理能力,導(dǎo)致性能下降甚至崩潰。通過限流,可以平滑處理請求,防止服務(wù)器不堪重負(fù)。
- Nginx限流配置: 在 Nginx 中,限流通常通過 ngx_http_limit_req_module 模塊來實(shí)現(xiàn)。該模塊允許你定義請求的速率限制,以及對超出限制的請求進(jìn)行處理的方式,例如返回503錯誤或進(jìn)入排隊(duì)等待。
- 限流算法: Nginx 默認(rèn)使用令牌桶算法進(jìn)行限流。該算法基于令牌桶的概念,每個令牌代表一個請求。系統(tǒng)以一定的速率往令牌桶中放入令牌,請求時需要從令牌桶中取出令牌,當(dāng)令牌不足時進(jìn)行限流處理。
- 監(jiān)控和調(diào)優(yōu): 監(jiān)控 Nginx 的限流情況,并在需要時進(jìn)行調(diào)優(yōu)。監(jiān)控可以通過 Nginx 的日志或?qū)I(yè)監(jiān)控工具實(shí)現(xiàn),而調(diào)優(yōu)可能涉及到調(diào)整限流參數(shù)、合理設(shè)置令牌桶容量等。
2. Nginx 如何限流?
漏桶算法是一種經(jīng)典的流量控制算法,它以固定的速率接收請求,并以固定的速率處理請求,超過容量的請求將被丟棄或排隊(duì)等待。
在 Nginx 中,使用 ngx_http_limit_req_module 模塊來實(shí)現(xiàn)流量限制,其中漏桶算法是默認(rèn)的限流算法。
以下是漏桶算法在 Nginx 中的一般工作原理:
令牌桶初始化: 在配置中,使用 limit_req_zone 指令來定義一個共享內(nèi)存區(qū)域,作為令牌桶的存儲。這個令牌桶會以指定的速率生成令牌。
http {
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
# 其他配置...
}
令牌生成: 令牌桶以每秒1個的速率生成令牌。每個令牌表示一個允許通過的請求。
請求處理: 當(dāng)有請求到達(dá)時,Nginx 會嘗試從令牌桶中獲取一個令牌。如果成功獲取到令牌,請求將被處理;否則,請求將被拒絕或進(jìn)入排隊(duì)等待,具體取決于配置。
server {
location / {
limit_req zone=mylimit burst=5;
# 其他配置...
}
}
在這個例子中,burst=5表示在令牌桶為空時,允許瞬時突發(fā)的最大請求數(shù)為5。
漏桶補(bǔ)充: 每秒固定生成的令牌會不斷補(bǔ)充令牌桶,但令牌桶的容量是有限的。如果請求過多,超過了令牌桶的容量,多余的請求將被丟棄或進(jìn)行相應(yīng)的處理。
通過使用漏桶算法,Nginx能夠有效地控制請求的流量,防止過多的請求影響系統(tǒng)的穩(wěn)定性。這對于保護(hù)服務(wù)器免受突發(fā)大流量的沖擊是非常有用的。
3. Nginx 限流配置詳解
Nginx 限流需要使用 ngx_http_limit_req_module 模塊實(shí)現(xiàn)
“流量限制”配置兩個主要的指令,limit_req_zone 和 limit_req:
limit_req_zone 指令設(shè)置創(chuàng)建共享內(nèi)存區(qū),用于存儲限制請求的相關(guān)狀態(tài),但是它實(shí)際上并不限制請求速率的配置
拓展:共享內(nèi)存區(qū)域的作用
- 共享內(nèi)存區(qū)域是一種可以被多個進(jìn)程或線程同時訪問的內(nèi)存區(qū)域。
- 在 Nginx 中,
limit_req_zone指令定義的共享內(nèi)存區(qū)域用于存儲客戶端請求的限制信息,例如請求的時間戳、請求計(jì)數(shù)器等。多個nginx worker進(jìn)程可以同時訪問這個共享內(nèi)存區(qū)域,這樣就可以實(shí)現(xiàn)對客戶端請求的全局限制。 - 共享內(nèi)存區(qū)域的優(yōu)點(diǎn)是:訪問速度快、效率高,因?yàn)槎鄠€進(jìn)程可以直接訪問同一塊內(nèi)存, 避免了進(jìn)程間通信的開銷。
- 但是需要注意的是,共享內(nèi)存區(qū)域的大小是有限制的,如果定義的區(qū)域過小,可能會導(dǎo)致無法存儲足夠的請求信息,從而影響限制的效果。因此,在使用共享內(nèi)存區(qū)域時,需要根據(jù)實(shí)際情況選擇合適的大小。
- 所以需要通過添加
limit_req指令用于啟用前面定義的共享內(nèi)存區(qū),從而實(shí)際限制請求速率 - 應(yīng)用在特定的 location 或者 server 塊。
limit_req_zone 指令通常在HTTP塊中定義,它需要以下三個參數(shù):
limit_req_zone $variable zone=name:size rate=rate;$variable為限制的鍵值,可以是IP地址、HTTP頭部等;
name為共享內(nèi)存區(qū)域的名字;size為共享內(nèi)存區(qū)域的大?。?/li>rate為限制速率,即每秒鐘處理的請求數(shù)量。
4. Nginx 限流實(shí)驗(yàn)1
4.1. 環(huán)境準(zhǔn)備
| IP | 作用 | 備注 |
|---|---|---|
| 192.168.221.130 | nginx-proxy | 反向代理服務(wù)器 |
| 192.168.221.136 | nginx-backend | 后端服務(wù)器 |
| 192.168.221.138 | ab壓測服務(wù)器 | 對反向代理服務(wù)器對壓測 |
4.2. 后端服務(wù)器配置
//192.168.221.136配置:
[root@localhost conf.d]# vim login.conf
server {
listen 80;
server_name www.Jltlogin.com;
location /login {
root /usr/share/nginx/html;
index index.html index.html;
}
}
?
//配置html文件
[root@localhost ~]# vim /usr/share/nginx/html/login/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登錄頁面</title>
<style>
body {
background-color: #f2f2f2;
font-family: Arial;
}
.login-box {
width: 300px;
padding: 20px;
margin: 100px auto;
background-color: #fff;
border-radius: 10px;
}
h1 {
text-align: center;
}
input[type=text], input[type=password] {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
box-sizing: border-box;
border: 2px solid #ccc;
border-radius: 4px;
}
button[type=submit] {
width: 100%;
background-color: #4CAF50;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
border-radius: 4px;
cursor: pointer;
}
button[type=submit]:hover {
background-color: #45a049;
}
</style>
</head>?
<body>
<div class="login-box">
<h1>登錄</h1>
<form>
<label for="username">用戶名:</label>
<input type="text" id="username" name="username"><br><br>
<label for="password">密碼:</label>
<input type="password" id="password" name="password"><br><br>
<button type="submit">登錄</button>
</form>
</div>
</body>
</html>
?
[root@localhost login]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@localhost login]# systemctl restart nginx
本地host文件做好解析(windows中)
192.168.221.136 www.Jltlogin.com
瀏覽器訪問測試,保證源站訪問正常
http://www.Jltlogin.com/login
4.3. 反向代理服務(wù)器配置
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;?Key - 定義應(yīng)用限制的請求特性。示例中的 Nginx 變量$binary_remote_addr,保存客戶端IP地址的二進(jìn)制形式。
?Zone - 定義用于存儲每個IP地址狀態(tài)以及被限制請求URL訪問頻率的內(nèi)存區(qū)域。通過zone=mylimit 標(biāo)識區(qū)域的名字(自定義),冒號后面是區(qū)域大小。16000個IP地址的狀態(tài)信息,大約需要1MB。
?Rate - 連接請求。在該例子中,速率不能超過每秒1個請求。
#192.168.221.130
[root@localhost ~]$ cd /etc/nginx/conf.d/
[root@localhost conf.d]$ vim limit.conf
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
?
upstream myweb {
server 192.168.221.136:80 weight=1 max_fails=1 fail_timeout=1;
}
?
server {
listen 80;
server_name www.Jltlogin-proxy.com;
?
location /login {
limit_req zone=mylimit;
proxy_pass http://myweb;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
?
#不使用upstream
#limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
# server {
# listen 80;
# server_name www.Jltlogin-proxy.com;
# location /login {
# limit_req zone=mylimit;
# proxy_pass http://www.Jltlogin.com;
# proxy_set_header Host $host:$server_port;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# }
#}
?
#嘗試主配置文件http中修改添加,隱藏nginx版本
vim /etc/nginx/nginx.conf #在http中添加
server_tokens off;
配置本地host文件(138中,壓力測試)
192.168.221.136 www.Jltlogin.com?
配置本地host文件(windows中)
192.168.221.130 www.Jltlogin-proxy.com
?瀏覽器訪問測試
http://www.Jltlogin-proxy.com/login/
一秒一次/一秒鐘多次訪問(一秒多次按Ctrl+F5)
4.4. 對反向代理服務(wù)器進(jìn)行壓力測試
//192.168.221.138安裝壓力測試工具 [root@localhost ~]# yum install httpd-tools ? //添加hosts解析 [root@localhost ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 ? 192.168.221.130 www.Jltlogin-proxy.com ? [root@localhost ~]# curl -I www.Jltlogin-proxy.com/login HTTP/1.1 301 Moved Permanently Server: nginx/1.24.0 Date: Sat, 29 Jul 2023 09:51:58 GMT Content-Type: text/html Content-Length: 169 Connection: keep-alive Location: http://www.Jltlogin-proxy.com/login/ ? [root@localhost ~]# ab -n1000 -c2 http://www.Jltlogin-proxy.com/login -n 請求數(shù) -c 并發(fā)數(shù) ? //130代理機(jī)器看錯誤日志: [root@localhost nginx]# tailf /var/log/nginx/error.log 2023/07/29 17:55:28 [error] 3996#3996: *1053 limiting requests, excess: 0.112 by zone "mylimit", client: 192.168.221.136, server: www.Jltlogin-proxy.com, request: "GET /login HTTP/1.0", host: "www.Jltlogin-proxy.com"
日志字段
- limiting requests - 表明日志條目記錄的是被“流量限制”請求
- excess - 每毫秒超過對應(yīng)“流量限制”配置的請求數(shù)量
- zone - 定義實(shí)施“流量限制”的區(qū)域
- client - 發(fā)起請求的客戶端IP地址
- server - 服務(wù)器IP地址或主機(jī)名
- request - 客戶端發(fā)起的實(shí)際HTTP請求
- host - HTTP報(bào)頭中host的值
//130查看訪問日志出現(xiàn)503 [root@localhost nginx]# tail -f /var/log/nginx/access.log 192.168.221.136 - - [29/Jul/2023:17:55:28 +0800] "GET /login HTTP/1.0" 503 197 "-" "ApacheBench/2.3" "-"
5. Nginx 限流實(shí)驗(yàn)2
#192.168.221.130反向代理服務(wù)器操作
[root@localhost conf.d]$ cp limit.conf{,.bak}
[root@localhost conf.d]$ vim limit.conf
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
?
upstream myweb {
server 192.168.221.136:80 weight=1 max_fails=1 fail_timeout=1;
}
?
server {
listen 80;
server_name www.Jltlogin-proxy.com;
?
location /login {
limit_req zone=mylimit burst=5;
#limit_req zone=mylimit burst=5 nodelay;
proxy_pass http://myweb;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
burst=5 表示最大延遲請求數(shù)量不大于5。超出的請求返回503狀態(tài)碼。limit_req zone=mylimit burst=5;這意味著在任何給定的一秒鐘內(nèi),只有 5 個請求會被允許通過。如果超過了這個限制,請求將會被暫時延遲,直到可以被處理為止。
?limit_req zone=mylimit burst=5 nodelay;該指令與上一個指令非常相似,但是添加了 nodelay 參數(shù)。
這個參數(shù)的作用是在達(dá)到限速閾值時不會延遲請求的處理。也就是說,如果超過了限速閾值,請求將不會被延遲,而是立即被處理。這可能會對服務(wù)器的性能產(chǎn)生【負(fù)面】影響,因?yàn)榉?wù)器需要處理更多的請求。但是,這樣做可以提高用戶體驗(yàn),因?yàn)橛脩舨恍枰却埱蟊惶幚怼?/p>
?//?192.168.221.138壓力測試服務(wù)器操作: [root@localhost ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 //添加host解析 192.168.221.130 www.Jltlogin-proxy.com ? //開始做壓力測試 [root@localhost ~]# ab -n1000 -c50 http://www.Jltlogin-proxy.com/login ? ? //192.168.221.130 反向代理機(jī)器上面看日志 [root@localhost ~]# tail -f /var/log/nginx/access.log 192.168.221.130 - - [29/Jul/2023:21:08:23 +0800] "GET /login HTTP/1.0" 301 169 "-" "ApacheBench/2.3" "-" 192.168.221.130 - - [29/Jul/2023:21:08:23 +0800] "GET /login HTTP/1.0" 503 197 "-" "ApacheBench/2.3" "-"
#nodelay:不延遲轉(zhuǎn)發(fā)請求。
………
location /login {
#limit_req zone=mylimit burst=5;
limit_req zone=mylimit burst=5 nodelay;
#delay:延遲
proxy_pass http://myweb;
…………
[root@localhost conf.d]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@localhost conf.d]# systemctl restart nginx ? //138繼續(xù)進(jìn)行壓力測試 [root@localhost ~]# ab -n1000 -c50 http://www.Jltlogin-proxy.com/login //nodelay會使處理請求的速度變得要快很多,一下就處理完了 ? //192.168.221.130 反向代理機(jī)器上面看日志 [root@localhost ~]# tail -f /var/log/nginx/access.log 192.168.221.138 - - [29/Jul/2023:21:12:24 +0800] "GET /login HTTP/1.0" 301 169 "-" "ApacheBench/2.3" "-" 192.168.221.138 - - [29/Jul/2023:21:12:24 +0800] "GET /login HTTP/1.0" 503 197 "-" "ApacheBench/2.3" "-"
總結(jié):
如果不加nodelay只有burst的時候,只會延遲轉(zhuǎn)發(fā)請求超過限制的請求出現(xiàn)503錯誤
舉例來說,burst=5,那么1秒內(nèi)收到7個請求,會先處理前5個,第6和第7個請求會被推遲到下一秒處理,如果接下來很長時間依然超過5個請求,第6和第7個請求最后會收到503錯誤。
如果nodelay和burst參數(shù)都有,則不會延遲轉(zhuǎn)發(fā)請求,并且超出規(guī)定的請求次數(shù)會返回503
可以理解為nodelay確保所有請求都得到及時處理,但不會改變burst的限制效果,超限的請求仍會是503。
6. 自定義返回錯誤代碼
一般情況下,客戶端超過配置的流量限制時,Nginx 響應(yīng)狀態(tài)碼為 503(Service Temporarily Unavailable)。
我們可以使用 limit_req_status 指令來設(shè)置為其它狀態(tài)碼(例如下面的404狀態(tài)碼)
//130反向代理服務(wù)器操作:
[root@localhost conf.d]# vim limit.conf
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
?
upstream myweb {
server 192.168.221.136:80 weight=1 max_fails=1 fail_timeout=1;
}
?
server {
listen 80;
server_name www.Jltlogin-proxy.com;
?
location /login {
limit_req zone=mylimit;
limit_req_status 404; #自定義限流的錯誤代碼為404
proxy_pass http://myweb;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
?
[root@localhost conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@localhost conf.d]# systemctl restart nginx
?//138進(jìn)行壓力測試:
[root@nginx-yum ~]# ab -n10 -c5 http://www.Jltlogin-proxy.com/login
?//130反向代理服務(wù)器查看日志
[root@localhost conf.d]# tailf /var/log/nginx/access.log
192.168.221.138 - - [29/Jul/2023:21:17:33 +0800] "GET /login HTTP/1.0" 301 169 "-" "ApacheBench/2.3" "-"
192.168.221.138 - - [29/Jul/2023:21:17:33 +0800] "GET /login HTTP/1.0" 404 153 "-" "ApacheBench/2.3" "-"
//404 153:狀態(tài)碼、返回的數(shù)據(jù)長度,單位通常是字節(jié)(byte)到此這篇關(guān)于Nginx 流量控制/限流的具體實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Nginx 流量控制/限流內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
nginx使用IPV6的相關(guān)配置項(xiàng)介紹
這篇文章主要介紹了nginx使用IPV6的相關(guān)配置項(xiàng)介紹,首先查看編譯參數(shù)是否編譯了IPV6模塊,然后介紹了監(jiān)聽IPV6的配置語法,需要的朋友可以參考下2014-07-07
Nginx配置Vue項(xiàng)目Hash/History模式路由跳轉(zhuǎn)錯誤的解決方案
這篇文章主要為大家詳細(xì)介紹了Nginx配置Vue項(xiàng)目Hash/History模式路由跳轉(zhuǎn)錯誤的相關(guān)解決方案,文中的示例代碼講解詳細(xì),需要的小伙伴可以了解下2025-09-09
在Linux和Windows系統(tǒng)上安裝Nginx服務(wù)器的教程
這篇文章主要介紹了在Linux和Windows系統(tǒng)上安裝Nginx服務(wù)器的教程,Linux系統(tǒng)這里以CentOS為代表,需要的朋友可以參考下2015-08-08
Nginx負(fù)載均衡之upstream模塊簡介與使用詳解
nginx有一個最大的功能就是可以實(shí)現(xiàn)服務(wù)器的負(fù)載均衡,下面這篇文章主要給大家介紹了關(guān)于Nginx負(fù)載均衡之upstream模塊簡介與使用的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09
nginx反向代理用做內(nèi)網(wǎng)域名轉(zhuǎn)發(fā)
這篇文章主要為大家詳細(xì)介紹了nginx反向代理用做內(nèi)網(wǎng)域名轉(zhuǎn)發(fā),具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-10-10

