Nginx 流量控制/限流的具體實現(xiàn)示例
1. Nginx 限流介紹
Nginx 限流是一種用于控制并發(fā)連接數(shù)或請求速率的機制,旨在保護服務(wù)器免受過多的請求影響,防止因請求過載而導(dǎo)致系統(tǒng)性能下降或崩潰。對 Nginx 限流的介紹可能涉及以下幾個關(guān)鍵點:
- 什么是限流: 限流是一種流量控制手段,用于限制單位時間內(nèi)可以通過系統(tǒng)的請求數(shù)或連接數(shù)。這有助于防止系統(tǒng)超負荷運行,保持系統(tǒng)的穩(wěn)定性和可用性。
- 為何需要限流: 在高并發(fā)的網(wǎng)絡(luò)環(huán)境中,突然涌入的大量請求可能會超出服務(wù)器的處理能力,導(dǎo)致性能下降甚至崩潰。通過限流,可以平滑處理請求,防止服務(wù)器不堪重負。
- Nginx限流配置: 在 Nginx 中,限流通常通過 ngx_http_limit_req_module 模塊來實現(xiàn)。該模塊允許你定義請求的速率限制,以及對超出限制的請求進行處理的方式,例如返回503錯誤或進入排隊等待。
- 限流算法: Nginx 默認使用令牌桶算法進行限流。該算法基于令牌桶的概念,每個令牌代表一個請求。系統(tǒng)以一定的速率往令牌桶中放入令牌,請求時需要從令牌桶中取出令牌,當令牌不足時進行限流處理。
- 監(jiān)控和調(diào)優(yōu): 監(jiān)控 Nginx 的限流情況,并在需要時進行調(diào)優(yōu)。監(jiān)控可以通過 Nginx 的日志或?qū)I(yè)監(jiān)控工具實現(xiàn),而調(diào)優(yōu)可能涉及到調(diào)整限流參數(shù)、合理設(shè)置令牌桶容量等。
2. Nginx 如何限流?
漏桶算法是一種經(jīng)典的流量控制算法,它以固定的速率接收請求,并以固定的速率處理請求,超過容量的請求將被丟棄或排隊等待。
在 Nginx 中,使用 ngx_http_limit_req_module
模塊來實現(xiàn)流量限制,其中漏桶算法是默認的限流算法。
以下是漏桶算法在 Nginx 中的一般工作原理:
令牌桶初始化: 在配置中,使用 limit_req_zone
指令來定義一個共享內(nèi)存區(qū)域,作為令牌桶的存儲。這個令牌桶會以指定的速率生成令牌。
http { limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s; # 其他配置... }
令牌生成: 令牌桶以每秒1個的速率生成令牌。每個令牌表示一個允許通過的請求。
請求處理: 當有請求到達時,Nginx 會嘗試從令牌桶中獲取一個令牌。如果成功獲取到令牌,請求將被處理;否則,請求將被拒絕或進入排隊等待,具體取決于配置。
server { location / { limit_req zone=mylimit burst=5; # 其他配置... } }
在這個例子中,burst=5
表示在令牌桶為空時,允許瞬時突發(fā)的最大請求數(shù)為5。
漏桶補充: 每秒固定生成的令牌會不斷補充令牌桶,但令牌桶的容量是有限的。如果請求過多,超過了令牌桶的容量,多余的請求將被丟棄或進行相應(yīng)的處理。
通過使用漏桶算法,Nginx能夠有效地控制請求的流量,防止過多的請求影響系統(tǒng)的穩(wěn)定性。這對于保護服務(wù)器免受突發(fā)大流量的沖擊是非常有用的。
3. Nginx 限流配置詳解
Nginx 限流需要使用 ngx_http_limit_req_module
模塊實現(xiàn)
“流量限制”配置兩個主要的指令,limit_req_zone
和 limit_req
:
limit_req_zone
指令設(shè)置創(chuàng)建共享內(nèi)存區(qū),用于存儲限制請求的相關(guān)狀態(tài),但是它實際上并不限制請求速率的配置
拓展:共享內(nèi)存區(qū)域的作用
- 共享內(nèi)存區(qū)域是一種可以被多個進程或線程同時訪問的內(nèi)存區(qū)域。
- 在 Nginx 中,
limit_req_zone
指令定義的共享內(nèi)存區(qū)域用于存儲客戶端請求的限制信息,例如請求的時間戳、請求計數(shù)器等。多個nginx worker進程可以同時訪問這個共享內(nèi)存區(qū)域,這樣就可以實現(xiàn)對客戶端請求的全局限制。 - 共享內(nèi)存區(qū)域的優(yōu)點是:訪問速度快、效率高,因為多個進程可以直接訪問同一塊內(nèi)存, 避免了進程間通信的開銷。
- 但是需要注意的是,共享內(nèi)存區(qū)域的大小是有限制的,如果定義的區(qū)域過小,可能會導(dǎo)致無法存儲足夠的請求信息,從而影響限制的效果。因此,在使用共享內(nèi)存區(qū)域時,需要根據(jù)實際情況選擇合適的大小。
- 所以需要通過添加
limit_req
指令用于啟用前面定義的共享內(nèi)存區(qū),從而實際限制請求速率 - 應(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ū)域的大??;rate
為限制速率,即每秒鐘處理的請求數(shù)量。
4. Nginx 限流實驗1
4.1. 環(huá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地址的二進制形式。
?Zone - 定義用于存儲每個IP地址狀態(tài)以及被限制請求URL訪問頻率的內(nèi)存區(qū)域。通過zone=mylimit
標識區(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ù)器進行壓力測試
//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代理機器看錯誤日志: [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 - 定義實施“流量限制”的區(qū)域
- client - 發(fā)起請求的客戶端IP地址
- server - 服務(wù)器IP地址或主機名
- request - 客戶端發(fā)起的實際HTTP請求
- host - HTTP報頭中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 限流實驗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ù)的作用是在達到限速閾值時不會延遲請求的處理。也就是說,如果超過了限速閾值,請求將不會被延遲,而是立即被處理。這可能會對服務(wù)器的性能產(chǎn)生【負面】影響,因為服務(wù)器需要處理更多的請求。但是,這樣做可以提高用戶體驗,因為用戶不需要等待請求被處理。
?//?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 反向代理機器上面看日志 [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ù)進行壓力測試 [root@localhost ~]# ab -n1000 -c50 http://www.Jltlogin-proxy.com/login //nodelay會使處理請求的速度變得要快很多,一下就處理完了 ? //192.168.221.130 反向代理機器上面看日志 [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進行壓力測試: [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 流量控制/限流的具體實現(xiàn)示例的文章就介紹到這了,更多相關(guān)Nginx 流量控制/限流內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Nginx之location匹配和Rewrite重寫跳轉(zhuǎn)方式
這篇文章主要介紹了Nginx之location匹配和Rewrite重寫跳轉(zhuǎn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06Nginx代理proxy pass配置去除前綴的實現(xiàn)
這篇文章主要介紹了Nginx代理proxy pass配置去除前綴的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10Nginx服務(wù)500:Internal Server Error原因之一
這篇文章主要介紹了Nginx服務(wù)500:Internal Server Error原因之一,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05Nginx stream 配置代理(Nginx TCP/UDP 負載均衡)
本文主要介紹了Nginx stream 配置代理(Nginx TCP/UDP 負載均衡),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11利用Nginx實現(xiàn)資源代理和接口代理的實現(xiàn)方法
在 Web 開發(fā)與部署中,我們常常需要借助 Nginx 實現(xiàn)接口代理和靜態(tài)資源代理,以解決跨域、統(tǒng)一入口、權(quán)限控制或性能優(yōu)化等問題,本指南將全面介紹 Nginx 資源代理與接口代理的實現(xiàn)方法,需要的朋友可以參考下2025-04-04Nginx中roxy_set_header與add_header區(qū)別舉例淺析
proxy_set_header是一個 Nginx 配置指令,用于設(shè)置將要轉(zhuǎn)發(fā)到后端服務(wù)器的 HTTP 請求頭,這篇文章主要給大家介紹了關(guān)于Nginx中roxy_set_header與add_header區(qū)別的相關(guān)資料,需要的朋友可以參考下2024-04-04