欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品

主頁 > 知識庫 > 人人都能看懂的 6 種限流實現方案(純干貨)

人人都能看懂的 6 種限流實現方案(純干貨)

熱門標簽:海南人工外呼系統哪家好 高德地圖標注公司位置需要錢嗎 怎么去掉地圖標注文字 合肥阿里辦理400電話號 慶陽外呼系統定制開發 北京外呼系統咨詢電話 地圖標注資源分享注冊 襄陽外呼增值業務線路解決方案 廊坊地圖標注申請入口

為了上班方便,去年我把自己在北郊的房子租出去了,搬到了南郊,這樣離我上班的地方就近了,它為我節約了很多的時間成本,我可以用它來做很多有意義的事,最起碼不會因為堵車而鬧心了,幸福感直線上升。

但即使這樣,生活也有其他的煩惱。南郊的居住密度比較大,因此停車就成了頭痛的事,我租的是路兩邊的非固定車位,每次只要下班回來,一定是沒有車位停了,因此我只能和別人的車并排停著,但這樣帶來的問題是,我每天早上都要被挪車的電話給叫醒,心情自然就不用說了。

但后來幾天,我就慢慢變聰明了,我頭天晚上停車的時候,會找第二天限行的車并排停著,這樣我第二天就不用挪車了,這真是限行給我帶來的“巨大紅利”啊。

而車輛限行就是一種生活中很常見的限流策略,他除了給我帶來了以上的好處之外,還給我們美好的生活環境帶來了一絲改善,并且快速增長的私家車已經給我們的交通帶來了巨大的“負擔”,如果再不限行,可能所有的車都要被堵在路上,這就是限流給我們的生活帶來的巨大好處。

從生活回到程序中,假設一個系統只能為 10W 人提供服務,突然有一天因為某個熱點事件,造成了系統短時間內的訪問量迅速增加到了 50W,那么導致的直接結果是系統崩潰,任何人都不能用系統了,顯然只有少人數能用遠比所有人都不能用更符合我們的預期,因此這個時候我們要使用「限流」了。

限流分類

限流的實現方案有很多種,磊哥這里稍微理了一下,限流的分類如下所示:

  • 合法性驗證限流:比如驗證碼、IP 黑名單等,這些手段可以有效的防止惡意攻擊和爬蟲采集;
  • 容器限流:比如 Tomcat、Nginx 等限流手段,其中 Tomcat 可以設置最大線程數(maxThreads),當并發超過最大線程數會排隊等待執行;而 Nginx 提供了兩種限流手段:一是控制速率,二是控制并發連接數;
  • 服務端限流:比如我們在服務器端通過限流算法實現限流,此項也是我們本文介紹的重點。

合法性驗證限流為最常規的業務代碼,就是普通的驗證碼和 IP 黑名單系統,本文就不做過多的敘述了,我們重點來看下后兩種限流的實現方案:容器限流和服務端限流。

容器限流

Tomcat 限流

Tomcat 8.5 版本的最大線程數在 conf/server.xml 配置中,如下所示:

Connector port="8080" protocol="HTTP/1.1"
     connectionTimeout="20000"
     maxThreads="150"
     redirectPort="8443" />

其中 maxThreads 就是 Tomcat 的最大線程數,當請求的并發大于此值(maxThreads)時,請求就會排隊執行,這樣就完成了限流的目的。

小貼士:maxThreads 的值可以適當的調大一些,此值默認為 150(Tomcat 版本 8.5.42),但這個值也不是越大越好,要看具體的硬件配置,需要注意的是每開啟一個線程需要耗用 1MB 的 JVM 內存空間用于作為線程棧之用,并且線程越多 GC 的負擔也越重。最后需要注意一下,操作系統對于進程中的線程數有一定的限制,Windows 每個進程中的線程數不允許超過 2000,Linux 每個進程中的線程數不允許超過 1000。

Nginx 限流

Nginx 提供了兩種限流手段:一是控制速率,二是控制并發連接數。

控制速率

我們需要使用 limit_req_zone 用來限制單位時間內的請求數,即速率限制,示例配置如下:

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s;
server { 
  location / { 
    limit_req zone=mylimit;
  }
}

以上配置表示,限制每個 IP 訪問的速度為 2r/s,因為 Nginx 的限流統計是基于毫秒的,我們設置的速度是 2r/s,轉換一下就是 500ms 內單個 IP 只允許通過 1 個請求,從 501ms 開始才允許通過第 2 個請求。

我們使用單 IP 在 10ms 內發并發送了 6 個請求的執行結果如下:

從以上結果可以看出他的執行符合我們的預期,只有 1 個執行成功了,其他的 5 個被拒絕了(第 2 個在 501ms 才會被正常執行)。

速率限制升級版

上面的速率控制雖然很精準但是應用于真實環境未免太苛刻了,真實情況下我們應該控制一個 IP 單位總時間內的總訪問次數,而不是像上面那么精確但毫秒,我們可以使用 burst 關鍵字開啟此設置,示例配置如下:

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s;
server { 
  location / { 
    limit_req zone=mylimit burst=4;
  }
}

burst=4 表示每個 IP 最多允許4個突發請求,如果單個 IP 在 10ms 內發送 6 次請求的結果如下:

從以上結果可以看出,有 1 個請求被立即處理了,4 個請求被放到 burst 隊列里排隊執行了,另外 1 個請求被拒絕了。

控制并發數

利用 limit_conn_zone 和 limit_conn 兩個指令即可控制并發數,示例配置如下:

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
server {
  ...
  limit_conn perip 10;
  limit_conn perserver 100;
}

其中 limit_conn perip 10 表示限制單個 IP 同時最多能持有 10 個連接;limit_conn perserver 100 表示 server 同時能處理并發連接的總數為 100 個。

小貼士:只有當 request header 被后端處理后,這個連接才進行計數。

服務端限流

服務端限流需要配合限流的算法來執行,而算法相當于執行限流的“大腦”,用于指導限制方案的實現。

有人看到「算法」兩個字可能就暈了,覺得很深奧,其實并不是。算法就相當于操作某個事務的具體實現步驟匯總,其實并不難懂,不要被它的表象給嚇到哦~

限流的常見算法有以下三種:

  • 時間窗口算法
  • 漏桶算法
  • 令牌算法

接下來我們分別看來。

1.時間窗口算法

所謂的滑動時間算法指的是以當前時間為截止時間,往前取一定的時間,比如往前取 60s 的時間,在這 60s 之內運行最大的訪問數為 100,此時算法的執行邏輯為,先清除 60s 之前的所有請求記錄,再計算當前集合內請求數量是否大于設定的最大請求數 100,如果大于則執行限流拒絕策略,否則插入本次請求記錄并返回可以正常執行的標識給客戶端。

滑動時間窗口如下圖所示:

其中每一小個表示 10s,被紅色虛線包圍的時間段則為需要判斷的時間間隔,比如 60s 秒允許 100 次請求,那么紅色虛線部分則為 60s。

我們可以借助 Redis 的有序集合 ZSet 來實現時間窗口算法限流,實現的過程是先使用 ZSet 的 key 存儲限流的 ID,score 用來存儲請求的時間,每次有請求訪問來了之后,先清空之前時間窗口的訪問量,統計現在時間窗口的個數和最大允許訪問量對比,如果大于等于最大訪問量則返回 false 執行限流操作,負責允許執行業務邏輯,并且在 ZSet 中添加一條有效的訪問記錄,具體實現代碼如下。

我們借助 Jedis 包來操作 Redis,實現在 pom.xml 添加 Jedis 框架的引用,配置如下:

!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
dependency>
  groupId>redis.clients/groupId>
  artifactId>jedis/artifactId>
  version>3.3.0/version>
/dependency>

具體的 Java 實現代碼如下:

import redis.clients.jedis.Jedis;

public class RedisLimit {
  // Redis 操作客戶端
  static Jedis jedis = new Jedis("127.0.0.1", 6379);

  public static void main(String[] args) throws InterruptedException {
    for (int i = 0; i  15; i++) {
      boolean res = isPeriodLimiting("java", 3, 10);
      if (res) {
        System.out.println("正常執行請求:" + i);
      } else {
        System.out.println("被限流:" + i);
      }
    }
    // 休眠 4s
    Thread.sleep(4000);
    // 超過最大執行時間之后,再從發起請求
    boolean res = isPeriodLimiting("java", 3, 10);
    if (res) {
      System.out.println("休眠后,正常執行請求");
    } else {
      System.out.println("休眠后,被限流");
    }
  }

  /**
   * 限流方法(滑動時間算法)
   * @param key   限流標識
   * @param period  限流時間范圍(單位:秒)
   * @param maxCount 最大運行訪問次數
   * @return
   */
  private static boolean isPeriodLimiting(String key, int period, int maxCount) {
    long nowTs = System.currentTimeMillis(); // 當前時間戳
    // 刪除非時間段內的請求數據(清除老訪問數據,比如 period=60 時,標識清除 60s 以前的請求記錄)
    jedis.zremrangeByScore(key, 0, nowTs - period * 1000);
    long currCount = jedis.zcard(key); // 當前請求次數
    if (currCount >= maxCount) {
      // 超過最大請求次數,執行限流
      return false;
    }
    // 未達到最大請求數,正常執行業務
    jedis.zadd(key, nowTs, "" + nowTs); // 請求記錄 +1
    return true;
  }
}

以上程序的執行結果為:

正常執行請求:0

正常執行請求:1

正常執行請求:2

正常執行請求:3

正常執行請求:4

正常執行請求:5

正常執行請求:6

正常執行請求:7

正常執行請求:8

正常執行請求:9

被限流:10

被限流:11

被限流:12

被限流:13

被限流:14

休眠后,正常執行請求

此實現方式存在的缺點有兩個:

  • 使用 ZSet 存儲有每次的訪問記錄,如果數據量比較大時會占用大量的空間,比如 60s 允許 100W 訪問時;
  • 此代碼的執行非原子操作,先判斷后增加,中間空隙可穿插其他業務邏輯的執行,最終導致結果不準確。

2.漏桶算法

漏桶算法的靈感源于漏斗,如下圖所示:

滑動時間算法有一個問題就是在一定范圍內,比如 60s 內只能有 10 個請求,當第一秒時就到達了 10 個請求,那么剩下的 59s 只能把所有的請求都給拒絕掉,而漏桶算法可以解決這個問題。

漏桶算法類似于生活中的漏斗,無論上面的水流倒入漏斗有多大,也就是無論請求有多少,它都是以均勻的速度慢慢流出的。當上面的水流速度大于下面的流出速度時,漏斗會慢慢變滿,當漏斗滿了之后就會丟棄新來的請求;當上面的水流速度小于下面流出的速度的話,漏斗永遠不會被裝滿,并且可以一直流出。

漏桶算法的實現步驟是,先聲明一個隊列用來保存請求,這個隊列相當于漏斗,當隊列容量滿了之后就放棄新來的請求,然后重新聲明一個線程定期從任務隊列中獲取一個或多個任務進行執行,這樣就實現了漏桶算法。

上面我們演示 Nginx 的控制速率其實使用的就是漏桶算法,當然我們也可以借助 Redis 很方便的實現漏桶算法。

我們可以使用 Redis 4.0 版本中提供的 Redis-Cell 模塊,該模塊使用的是漏斗算法,并且提供了原子的限流指令,而且依靠 Redis 這個天生的分布式程序就可以實現比較完美的限流了。

Redis-Cell 實現限流的方法也很簡單,只需要使用一條指令 cl.throttle 即可,使用示例如下:

> cl.throttle mylimit 15 30 60
1)(integer)0 # 0 表示獲取成功,1 表示拒絕
2)(integer)15 # 漏斗容量
3)(integer)14 # 漏斗剩余容量
4)(integer)-1 # 被拒絕之后,多長時間之后再試(單位:秒)-1 表示無需重試
5)(integer)2 # 多久之后漏斗完全空出來

其中 15 為漏斗的容量,30 / 60s 為漏斗的速率。

3.令牌算法

在令牌桶算法中有一個程序以某種恒定的速度生成令牌,并存入令牌桶中,而每個請求需要先獲取令牌才能執行,如果沒有獲取到令牌的請求可以選擇等待或者放棄執行,如下圖所示:

我們可以使用 Google 開源的 guava 包,很方便的實現令牌桶算法,首先在 pom.xml 添加 guava 引用,配置如下:

!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
dependency>
  groupId>com.google.guava/groupId>
  artifactId>guava/artifactId>
  version>28.2-jre/version>
/dependency>

具體實現代碼如下:

import com.google.common.util.concurrent.RateLimiter;

import java.time.Instant;

/**
 * Guava 實現限流
 */
public class RateLimiterExample {
  public static void main(String[] args) {
    // 每秒產生 10 個令牌(每 100 ms 產生一個)
    RateLimiter rt = RateLimiter.create(10);
    for (int i = 0; i  11; i++) {
      new Thread(() -> {
        // 獲取 1 個令牌
        rt.acquire();
        System.out.println("正常執行方法,ts:" + Instant.now());
      }).start();
    }
  }
}

以上程序的執行結果為:

正常執行方法,ts:2020-05-15T14:46:37.175Z

正常執行方法,ts:2020-05-15T14:46:37.237Z

正常執行方法,ts:2020-05-15T14:46:37.339Z

正常執行方法,ts:2020-05-15T14:46:37.442Z

正常執行方法,ts:2020-05-15T14:46:37.542Z

正常執行方法,ts:2020-05-15T14:46:37.640Z

正常執行方法,ts:2020-05-15T14:46:37.741Z

正常執行方法,ts:2020-05-15T14:46:37.840Z

正常執行方法,ts:2020-05-15T14:46:37.942Z

正常執行方法,ts:2020-05-15T14:46:38.042Z

正常執行方法,ts:2020-05-15T14:46:38.142Z

從以上結果可以看出令牌確實是每 100ms 產生一個,而 acquire() 方法為阻塞等待獲取令牌,它可以傳遞一個 int 類型的參數,用于指定獲取令牌的個數。它的替代方法還有 tryAcquire(),此方法在沒有可用令牌時就會返回 false 這樣就不會阻塞等待了。當然 tryAcquire() 方法也可以設置超時時間,未超過最大等待時間會阻塞等待獲取令牌,如果超過了最大等待時間,還沒有可用的令牌就會返回 false。

注意:使用 guava 實現的令牌算法屬于程序級別的單機限流方案,而上面使用 Redis-Cell 的是分布式的限流方案。

總結

本文提供了 6 種具體的實現限流的手段,他們分別是:Tomcat 使用 maxThreads 來實現限流;Nginx 提供了兩種限流方式,一是通過 limit_req_zone 和 burst 來實現速率限流,二是通過 limit_conn_zonelimit_conn 兩個指令控制并發連接的總數。最后我們講了時間窗口算法借助 Redis 的有序集合可以實現,還有漏桶算法可以使用 Redis-Cell 來實現,以及令牌算法可以解決 Google 的 guava 包來實現。

需要注意的是借助 Redis 實現的限流方案可用于分布式系統,而 guava 實現的限流只能應用于單機環境。如果你嫌棄服務器端限流麻煩,甚至可以在不改代碼的情況下直接使用容器限流(Nginx 或 Tomcat),但前提是能滿足你的業務需求。

好了,文章到這里就結束了,期待我們下期再會~

參考 鳴謝

https://www.cnblogs.com/biglittleant/p/8979915.html

到此這篇關于人人都能看懂的 6 種限流實現方案(純干貨)的文章就介紹到這了,更多相關限流內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • nginx限流方案的實現(三種方式)
  • 高并發系統的限流詳解及實現
  • 使用nginx實現分布式限流的方法
  • 基于Redis實現分布式應用限流的方法
  • Go如何實現HTTP請求限流示例
  • 基于Redis的限流器的實現(示例講解)
  • 淺談Koa服務限流方法實踐
  • 來自CSDN的"無限流"分頁程序
  • nginx 如何實現讀寫限流的方法
  • 一文搞懂Nginx限流(簡單實現)

標簽:平頂山 鶴崗 臺州 鎮江 商丘 株洲 綿陽 哈密

巨人網絡通訊聲明:本文標題《人人都能看懂的 6 種限流實現方案(純干貨)》,本文關鍵詞  人,人都,能看,懂的,種,限流,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《人人都能看懂的 6 種限流實現方案(純干貨)》相關的同類信息!
  • 本頁收集關于人人都能看懂的 6 種限流實現方案(純干貨)的相關信息資訊供網民參考!
  • 推薦文章
    欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品
  • <rt id="w000q"><acronym id="w000q"></acronym></rt>
  • <abbr id="w000q"></abbr>
    <rt id="w000q"></rt>
    黄页网站大全一区二区| 中国黄色片视频| 国产一级淫片久久久片a级| 欧美一区二区三区成人| 亚洲国产日韩综合久久精品| caoporn国产一区二区| 五月婷婷一区二区| 中文字幕一区二区三区乱码在线| 国产激情视频一区二区在线观看 | 国产精品久久久久久久久免费相片 | 蜜桃传媒一区二区亚洲av| 7777精品伊人久久久大香线蕉完整版 | 亚洲成av人片在线| 国产伦精品一区二区三区精品| 欧美日韩亚洲综合在线 | 精品在线视频一区| 免费看的黄色网| 久久精品一二三| 国产精品白丝jk白祙喷水网站| 福利视频第一页| 国产精品―色哟哟| 不卡视频一二三四| 欧美最猛性xxxxx直播| 亚洲福利电影网| 99re久久精品国产| 人妻精品久久久久中文字幕69| 欧美性大战xxxxx久久久| 一区二区三区波多野结衣在线观看| 91麻豆蜜桃一区二区三区| 欧美三级电影网站| 日本中文字幕一区二区视频| 欧美黄色一级生活片| 国产女人aaa级久久久级| 岛国精品在线观看| 91黄色免费观看| 亚洲成人av免费| 熟女俱乐部一区二区| 国产亚洲成aⅴ人片在线观看 | 欧美h片在线观看| 亚洲日本一区二区| 日本三级日本三级日本三级极| 欧美不卡123| 国产成人av电影免费在线观看| 全程偷拍露脸中年夫妇| 亚洲一区二区影院| 三上悠亚ssⅰn939无码播放| 国产色产综合色产在线视频 | 色狠狠色狠狠综合| 亚洲国产色一区| 影音先锋男人在线| 亚洲少妇屁股交4| 深田咏美中文字幕| 久久久亚洲欧洲日产国码αv| 盗摄精品av一区二区三区| 欧美日韩免费一区二区三区视频| 老鸭窝一区二区久久精品| 777777国产7777777| 午夜精品福利一区二区三区av| 国精产品一区二区三区| 日韩毛片视频在线看| 亚洲精品女人久久久| 欧美国产精品久久| av在线天堂网| 国产欧美一二三区| 日韩精品国产一区| 国产日韩一级二级三级| 中文字幕第六页| 久久久777精品电影网影网 | 中文字幕欧美日韩一区| 日本xxxx免费| 国产欧美综合在线观看第十页| 极品人妻一区二区| 久久精品一二三| 少妇激情一区二区三区视频| 国产精品久久久久久久久搜平片| 成人无码www在线看免费| 国产精品久久久久久久久久免费看| 91精产国品一二三| 国产欧美视频在线观看| 久久久久国产精品区片区无码| 亚洲欧美在线视频观看| 九色porny自拍视频| 亚洲欧美国产77777| 亚洲成人黄色av| 亚洲电影视频在线| 日日骚一区二区三区| 九色综合狠狠综合久久| 欧美人伦禁忌dvd放荡欲情| 丁香啪啪综合成人亚洲小说 | 日韩一区二区三区在线视频| www.爱久久.com| 国产熟妇搡bbbb搡bbbb| 亚洲欧美综合另类在线卡通| 刘亦菲国产毛片bd| 免费在线视频一区| 精品视频色一区| av在线不卡网| 日本一区二区视频在线| a级在线免费观看| 日韩精品视频网| 欧美日韩三级视频| 99久久99久久免费精品蜜臀| 国产欧美日韩视频一区二区| 3d动漫精品啪啪一区二区下载| 亚洲午夜免费电影| 色婷婷综合激情| 国产xxx精品视频大全| 久久精品男人的天堂| 91中文字幕永久在线| 日韩高清不卡一区二区| 欧美日韩一级片在线观看| caoporn国产精品| 国产精品国产三级国产专播品爱网| 亚洲国产日韩一区无码精品久久久| 亚洲第一激情av| 破处女黄色一级片| 高清国产一区二区三区| 国产免费成人在线视频| 999精品久久久| 国产精品一区免费在线观看| 久久综合一区二区| 黄免费在线观看| 久久精工是国产品牌吗| 日韩精品一区二区三区视频播放| 久久久久麻豆v国产精华液好用吗| 亚洲1区2区3区视频| 欧美日韩国产另类不卡| 亚洲一级Av无码毛片久久精品| 亚洲国产精品人人做人人爽| 欧美日韩一级黄| 国产精品入口麻豆| 日韩制服丝袜av| 日韩免费成人网| 久久久久久久久久久久| 国内精品写真在线观看| 国产色一区二区| 丰满少妇高潮久久三区| 91免费国产在线| 亚洲无人区一区| 欧美一级夜夜爽| 色婷婷av777| 国产自产v一区二区三区c| 欧美国产综合色视频| 日韩一区二区不卡视频| 99国内精品久久| 亚洲国产视频一区| 日韩欧美高清dvd碟片| 四虎永久免费在线观看| 国产精选一区二区三区| 国产精品久久久久久久久动漫 | 日本午夜一本久久久综合| 日韩精品一区二区三区swag| 精品人伦一区二区| 精品电影一区二区| 成人欧美一区二区三区黑人一 | 国产成人综合在线观看| 亚洲欧美影音先锋| 欧美日韩国产综合草草| aaaaaav| 国产精品一区二区三区四区| 亚洲三级在线播放| 69精品人人人人| 精品国产aaa| av在线综合网| 日产国产高清一区二区三区| 国产日韩影视精品| 欧洲激情一区二区| 日韩人妻一区二区三区| 成人精品国产福利| 亚洲国产aⅴ天堂久久| 精品国产精品网麻豆系列 | 亚洲色图都市小说| 在线不卡的av| 日韩精品电影一区二区三区| av在线不卡免费看| 日本vs亚洲vs韩国一区三区 | 亚洲成av人片一区二区梦乃| 精品国产亚洲在线| a级片在线观看免费| 自拍视频一区二区| 丁香六月久久综合狠狠色| 午夜精品久久久久久久| 国产精品欧美久久久久一区二区| 欧美日韩在线精品一区二区三区激情| 公侵犯人妻一区二区三区| youjizz久久| 日本91福利区| 成人欧美一区二区三区黑人麻豆| 日韩欧美不卡一区| 91黄色激情网站| 性欧美13一14内谢| 91麻豆视频网站| 久久国产福利国产秒拍| 亚洲精品国产视频| 久久综合色鬼综合色| 精品1区2区3区| 老司机深夜福利网站| 日b视频在线观看| 不卡视频一二三四| 国产一区亚洲一区|