利用 Nginx 實現限流


在當下互聯網高並發時代中,項目往往會遇到需要限制客戶端連接的需求。我們熟知的 Nginx 就提供了有這樣的功能,可以簡單的實現對客戶端請求頻率,並發連接和傳輸速度的限制….

Nginx 限流

Nginx為我們提供了請求限制模塊(ngx_http_limit_req_module)、基於令牌桶算法的流量限制模塊(ngx_stream_limit_conn_module),可以方便的控制令牌速率,自定義調節限流,實現基本的限流控制…

請求限制

請求限制的功能來自於 ngx_http_limit_req_module 模塊。使用它需要首先在 http 配置段中定義限制的參照標准和狀態緩存區大小。

limit_req_zone 只能配置在 http 范圍內;

$binary_remote_addr 表示客戶端請求的IP地址;

mylimit 自己定義的變量名;

rate 請求頻率,每秒允許多少請求;

limit_req 與 limit_req_zone 對應,burst 表示緩存住的請求數,也就是任務隊列。

下面的配置就是定義了使用客戶端的 IP 作為參照依據,並使用一個 10M 大小的狀態緩存區。結尾的 rate=1r/s 表示針對每個 IP 的請求每秒只接受一次。

10M 的狀態緩存空間夠不夠用呢?官方給出的答案是 1M 的緩存空間可以在 32 位的系統中服務 3.2 萬 IP 地址,在 64 位的系統中可以服務 1.6 萬 IP 地址,所以需要自己看情況調整。如果狀態緩存耗光,后面所有的請求都會收到 503(Service Temporarily Unavailable) 錯誤。

腳本代碼

1
2
3
4
5
6
7
8
9
10
11
12
# 定義了一個 mylimit 緩沖區(容器),請求頻率為每秒 1 個請求(nr/s)
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
server {
listen 70;
location / {
# nodelay 不延遲處理
# burst 是配置超額處理,可簡單理解為隊列機制
# 上面配置同一個 IP 沒秒只能發送一次請求(1r/s),這里配置了緩存3個請求,就意味着同一秒內只能允許 4 個任務響應成功,其它任務請求則失敗(503錯誤)
limit_req zone=mylimit burst=3 nodelay;
proxy_pass http://localhost:7070;
}
}

測試代碼

為了方便此處提供 JAVA、AB 兩種測試代碼..

1
2
3
# -n 即指定壓力測試總共的執行次數
# -c 即指定的並發數
ab -n 5 -c 5 http://192.168.0.133:70/index
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.battcn.limiting;

import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* @author Levin
* @since 2018/7/27 0027
*/
public class NginxLimiterTest {

public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(5);
for (int i = 0; i < 6; i++) {
CompletableFuture.supplyAsync(() -> {
final ResponseEntity<String> entity = new RestTemplate().getForEntity("http://192.168.0.133:70/index", String.class);
return entity.getBody();
}, service).thenAccept(System.out::println);
}
service.shutdown();
}
}

測試日志

此處提供 AB 測試結果 JAVA 的日志就不貼了,5個請求其中一個請求是有問題的,出問題的那個就是被拒絕請求的…

1
2
3
4
5
6
7
8
9
[root@localhost myconf]# ab -n 5 -c 5 http://192.168.0.133:70/index
Document Path: /index
Document Length: 34 bytes

Concurrency Level: 5
Time taken for tests: 0.002 seconds
Complete requests: 5
Failed requests: 1
(Connect: 0, Receive: 0, Length: 1, Exceptions: 0)

並發限制

Nginx 並發限制的功能來自於 ngx_http_limit_conn_module 模塊,跟請求配置一樣,使用它之前,需要先定義參照標准和狀態緩存區。

limit_conn_zone 只能配置在 http 范圍內;

$binary_remote_addr 表示客戶端請求的IP地址;

myconn 自己定義的變量名(緩沖區);

limit_rate 限制傳輸速度

limit_conn 與 limit_conn_zone 對應,限制網絡連接數

下面的配置就是定義了使用客戶端的 IP 作為參照依據,並使用一個 10M 大小的狀態緩存區。限定了每個IP只允許建立一個請求連接,同時傳輸的速度最大為 1024KB

腳本代碼

1
2
3
4
5
6
7
8
9
10
11
12
# 定義了一個 myconn 緩沖區(容器)
limit_conn_zone $binary_remote_addr zone=myconn:10m;
server {
listen 70;
location / {
# 每個 IP 只允許一個連接
limit_conn myconn 1;
# 限制傳輸速度(如果有N個並發連接,則是 N * limit_rate)
limit_rate 1024k;
proxy_pass http://localhost:7070;
}
}

說點什么

請求限流方面自己寫一個簡單的 Spring Boot 程序部署到服務器配置好 Nginx 映射即可,並發限流弄一個大文件下載,或者讓自己服務接口在內部休眠一定時間就能測試出效果….

參考文獻


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM