利用 Nginx 實現限流

在當下互聯網高併發時代中,項目每每會遇到須要限制客戶端鏈接的需求。咱們熟知的 Nginx 就提供了有這樣的功能,能夠簡單的實現對客戶端請求頻率,併發鏈接和傳輸速度的限制....html

Nginx 限流

Nginx爲咱們提供了請求限制模塊( ngx_http_limit_req_module)、基於令牌桶算法的流量限制模塊( ngx_stream_limit_conn_module),能夠方便的控制令牌速率,自定義調節限流,實現基本的限流控制...java

請求限制

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

limit_req_zone 只能配置在 http 範圍內;nginx

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

mylimit 本身定義的變量名;github

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

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

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

10M 的狀態緩存空間夠不夠用呢?官方給出的答案是 1M 的緩存空間能夠在 32 位的系統中服務 3.2 萬 IP 地址,在 64 位的系統中能夠服務 1.6 萬 IP 地址,因此須要本身看狀況調整。若是狀態緩存耗光,後面全部的請求都會收到 503(Service Temporarily Unavailable) 錯誤。shell

腳本代碼

  
    
  
  
  
   
   
            
   
   
# 定義了一個 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;    }}

測試代碼

爲了方便此處提供 JAVAAB 兩種測試代碼..

  
    
  
  
  
   
   
            
   
   
# -n 即指定壓力測試總共的執行次數# -c 即指定的併發數ab -n 5 -c 5 http://192.168.0.133:70/index
  
    
  
  
  
   
   
            
   
   
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個請求其中一個請求是有問題的,出問題的那個就是被拒絕請求的...

  
    
  
  
  
   
   
            
   
   
[root@localhost myconf]# ab -n 5 -c 5 http://192.168.0.133:70/indexDocument Path:          /indexDocument Length:        34 bytesConcurrency Level:      5Time taken for tests:   0.002 secondsComplete requests:      5Failed 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

腳本代碼

  
    
  
  
  
   
   
            
   
   
# 定義了一個 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;    }}

說點什麼

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

參考文獻

  • ngx_http_limit_req_module http://nginx.org/en/docs/http/ngxhttplimitreqmodule.html

  • ngx_http_limit_conn_module http://nginx.org/en/docs/http/ngxhttplimitconnmodule.html

  • ngx_http_core_module http://nginx.org/en/docs/http/ngxhttpcoremodule.html

總結

限流不必定會提高性能,但使用好限流手段卻可保障服務的穩定性、可靠性,使服務更爲的健壯....

說點什麼

  • 我的QQ:1837307557

  • battcn開源羣(適合新手):391619659

  • 微信公衆號(歡迎調戲): battcn

我的博客:http://blog.battcn.com/

全文代碼:https://github.com/battcn/spring-boot2-learning/tree/master/chapter26


本文分享自微信公衆號 - battcn(battcn)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索