高并發(fā)場景下的限流和降級

什么是限流和降級

在開發(fā)高并發(fā)系統(tǒng)時击儡,有很多手段來保護系統(tǒng):緩存、降級蝠引、限流阳谍。

當訪問量快速增長、服務可能會出現一些問題(響應超時)螃概,或者會存在非核心服 務影響到核心流程的性能時矫夯, 仍然需要保證服務的可用性,即便是有損服務吊洼。 所以意味著我們在設計服務的時候训貌,需要一些手段或者關鍵數據進行自動降級,或者配置人工降級的開關冒窍。

緩存的目的是提升系統(tǒng)訪問速度和增大系統(tǒng)處理的容量递沪,可以說是抗高并發(fā)流量的銀彈;

降級是當服務出問題或者影響到核心流程的性能則需要暫時屏蔽掉某些功能,等高 峰或者問題解決后再打開;而有些場景并不能用緩存和降級來解決综液,比如秒殺款慨、搶 購;寫服務(評論、下單)谬莹、頻繁的復雜查詢檩奠,因此需要一種手段來限制這些場景 的并發(fā)/請求量

降級

對于高可用服務的設計桩了,有一個很重要的設計,那就是降級埠戳。降級一般有幾種實現 手段井誉,自動降級和人工降級

  1. 通過配置降級開關,實現對流程的控制

  2. 前置化降級開關整胃, 基于 OpenResty+配置中心實現降級

  3. 業(yè)務降級颗圣,在大促的時候,我們會有限保證核心業(yè)務的流程可用屁使,也就是下單 支付在岂。同時,我們也會對核心的支付流程采取一些異步化的方式來提升吞吐量

限流

限流的目的是防止惡意請求流量屋灌、惡意攻擊、或者防止流量超過系統(tǒng)峰值 限流是對資源訪問做控制的一個組件或者功能应狱,那么控制這塊主要有兩個功能:限流策略和熔斷策略共郭,對于熔斷策略,不同的系統(tǒng)有不同的熔斷策略訴求疾呻,有得系統(tǒng)希望直接拒絕服務除嘹、有的系統(tǒng)希望排隊等待、有的系統(tǒng)希望服務降級岸蜗。限流服務 這塊有兩個核心概念:資源和策略資源:被流量控制的對象尉咕,比如接口策略:限流策略由限流算法和可調節(jié)的參數兩部份組成

限流的目的是通過對并發(fā)訪問/請求進行限速或者一個時間窗口內的請求進行限速 來保護系統(tǒng),一旦達到限制速率則可以拒絕服務(定向到錯誤頁或者告知資源沒有 了)璃岳、排隊或等待(秒殺年缎、下單)、降級(返回兜底數據或默認數據或默認數據铃慷,如商品詳情頁庫存默認有貨)

限流和降級

滑動窗口協(xié)議是傳輸層進行流控的一種措施单芜,接收方通過通告發(fā)送方自己的窗口大小,從而控制發(fā)送方的發(fā)送速度犁柜,從而達到防止發(fā)送方發(fā)送速度過快而導致自己被淹沒的目的洲鸠。

簡單解釋下,發(fā)送和接受方都會維護一個數據幀的序列馋缅,這個序列被稱作窗口扒腕。發(fā) 送方的窗口大小由接受方確定,目的在于控制發(fā)送速度萤悴,以免接受方的緩存不夠大瘾腰, 而導致溢出,同時控制流量也可以避免網絡擁塞覆履。下面圖中的 4,5,6 號數據幀已經 被發(fā)送出去居灯,但是未收到關聯(lián)的 ACK祭务,7,8,9 幀則是等待發(fā)送」窒樱可以看出發(fā)送端的 窗口大小為 6义锥,這是由接受端告知的。此時如果發(fā)送端收到 4 號 ACK岩灭,則窗口的左 邊緣向右收縮拌倍,窗口的右邊緣則向右擴展,此時窗口就向前“滑動了”噪径,即數據幀 10 也可以被發(fā)送

動態(tài)效果演示

什么是限流和降級

在開發(fā)高并發(fā)系統(tǒng)時柱恤,有很多手段來保護系統(tǒng):緩存、降級找爱、限流梗顺。

當訪問量快速增長、服務可能會出現一些問題(響應超時)车摄,或者會存在非核心服 務影響到核心流程的性能時寺谤, 仍然需要保證服務的可用性,即便是有損服務吮播。 所以意味著我們在設計服務的時候变屁,需要一些手段或者關鍵數據進行自動降級,或者配置人工降級的開關意狠。

緩存的目的是提升系統(tǒng)訪問速度和增大系統(tǒng)處理的容量粟关,可以說是抗高并發(fā)流量的銀彈;

降級是當服務出問題或者影響到核心流程的性能則需要暫時屏蔽掉某些功能,等高 峰或者問題解決后再打開;而有些場景并不能用緩存和降級來解決环戈,比如秒殺闷板、搶 購;寫服務(評論、下單)院塞、頻繁的復雜查詢蛔垢,因此需要一種手段來限制這些場景 的并發(fā)/請求量

降級

對于高可用服務的設計,有一個很重要的設計迫悠,那就是降級鹏漆。降級一般有幾種實現 手段,自動降級和人工降級

  1. 通過配置降級開關创泄,實現對流程的控制

  2. 前置化降級開關艺玲, 基于 OpenResty+配置中心實現降級

  3. 業(yè)務降級,在大促的時候鞠抑,我們會有限保證核心業(yè)務的流程可用饭聚,也就是下單 支付。同時搁拙,我們也會對核心的支付流程采取一些異步化的方式來提升吞吐量

限流

限流的目的是防止惡意請求流量秒梳、惡意攻擊法绵、或者防止流量超過系統(tǒng)峰值 限流是對資源訪問做控制的一個組件或者功能,那么控制這塊主要有兩個功能:限流策略和熔斷策略酪碘,對于熔斷策略朋譬,不同的系統(tǒng)有不同的熔斷策略訴求,有得系統(tǒng)希望直接拒絕服務兴垦、有的系統(tǒng)希望排隊等待徙赢、有的系統(tǒng)希望服務降級。限流服務 這塊有兩個核心概念:資源和策略資源:被流量控制的對象探越,比如接口策略:限流策略由限流算法和可調節(jié)的參數兩部份組成

限流的目的是通過對并發(fā)訪問/請求進行限速或者一個時間窗口內的請求進行限速 來保護系統(tǒng)狡赐,一旦達到限制速率則可以拒絕服務(定向到錯誤頁或者告知資源沒有 了)、排隊或等待(秒殺钦幔、下單)枕屉、降級(返回兜底數據或默認數據或默認數據,如商品詳情頁庫存默認有貨)

限流和降級

滑動窗口協(xié)議是傳輸層進行流控的一種措施鲤氢,接收方通過通告發(fā)送方自己的窗口大小搀擂,從而控制發(fā)送方的發(fā)送速度,從而達到防止發(fā)送方發(fā)送速度過快而導致自己被淹沒的目的铜异。

簡單解釋下哥倔,發(fā)送和接受方都會維護一個數據幀的序列秸架,這個序列被稱作窗口揍庄。發(fā) 送方的窗口大小由接受方確定,目的在于控制發(fā)送速度东抹,以免接受方的緩存不夠大蚂子, 而導致溢出,同時控制流量也可以避免網絡擁塞缭黔。下面圖中的 4,5,6 號數據幀已經 被發(fā)送出去食茎,但是未收到關聯(lián)的 ACK,7,8,9 幀則是等待發(fā)送馏谨”鹩妫可以看出發(fā)送端的 窗口大小為 6,這是由接受端告知的惧互。此時如果發(fā)送端收到 4 號 ACK哎媚,則窗口的左 邊緣向右收縮,窗口的右邊緣則向右擴展喊儡,此時窗口就向前“滑動了”拨与,即數據幀 10 也可以被發(fā)送

動態(tài)效果演示

漏桶

image-20181127153258192.png

桶本身具有一個恒定的速率往下漏水,而上方時快時慢的會有水進入桶內艾猜。當桶還 未滿時买喧,上方的水可以加入捻悯。一旦水滿,上方的水就無法加入淤毛。桶滿正是算法中的 一個關鍵的觸發(fā)條件(即流量異常判斷成立的條件)今缚。而此條件下如何處理上方流 下來的水,有兩種方式:

  1. 暫時攔截住上方水的向下流動钱床,等待桶中的一部分水漏走后荚斯,再放行上方水。

  2. 溢出的上方水直接拋棄 特點

  3. 漏水的速率是固定的

  4. 即使存在注水 burst(突然注水量變大)的情況查牌,漏水的速率也是固定的

令牌桶(能夠解決突發(fā)流量)

令牌桶算法是網絡流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一種算法事期。典型情況下,令牌桶算法用來控制發(fā)送到網絡上的數據的數目纸颜,并允許突發(fā)數據的發(fā)送兽泣。

令牌桶是一個存放固定容量令牌(token)的桶,按照固定速率往桶里添加令牌; 令牌桶算法實際上由三部分組成:兩個流和一個桶胁孙,分別是令牌流唠倦、數據流和令牌桶

image-20181127153946953.png

限流算法的實際應用

Guava 的 RateLimiter 實現

在 Guava 中 RateLimiter 的實現有兩種: Bursty 和 WarmUp

bursty

bursty 是基于 token bucket 的算法實現,比如

RateLimiter rateLimiter=RateLimiter.create(permitPerSecond); //創(chuàng)建一個 bursty 實例

rateLimiter.acquire(); //獲取 1 個 permit涮较,當令牌數量不夠時會阻塞直到獲取為止

WarmingUp

  1. 基于 Leaky bucket 算法實現

  2. QPS 是固定的

  3. 使用于需要預熱時間的使用場景

//創(chuàng)建一個 SmoothWarmingUp 實例;warmupPeriod 是指預熱的時間 
RateLimiter create(double permitsPerSecond, long warmupPeriod, TimeUnit unit) 

RateLimiter rateLimiter =RateLimiter.create(permitsPerSecond,warmupPeriod,timeUnit); 

rateLimiter.acquire();//獲取 1 個 permit;可能會被阻塞止到獲取到為止 

 <dependency>
     <groupId>com.google.guava</groupId>
     <artifactId>guava</artifactId>
     <version>27.0-jre</version>
</dependency>
public class Token {
    //guava->令牌桶稠鼻、漏桶
    //bursty(令牌桶)
    RateLimiter rateLimiter=RateLimiter.create(10); //qps是1000

    //漏桶
    RateLimiter rateLimiter1=RateLimiter.create(1000,10, TimeUnit.MILLISECONDS);

    public void doPay(){
        if(rateLimiter.tryAcquire()){
            System.out.println(Thread.currentThread().getName()+"開始執(zhí)行支付");
        }else {
            System.out.println("系統(tǒng)繁忙");
        }
    }

    public static void main(String[] args) throws IOException {
        Token token=new Token();
        CountDownLatch countDownLatch=new CountDownLatch(1);
        Random random=new Random(10);
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                try{
                    countDownLatch.await();
                    Thread.sleep(random.nextInt(1000));
                    token.doPay();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        countDownLatch.countDown();
        System.in.read();
    }
}

差異化演示

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

import java.util.concurrent.TimeUnit;

public class TokenDemo {
    private int qps;
    private int countOfReq;
    private RateLimiter rateLimiter;

    public TokenDemo(int qps, int countOfReq) {
        this.qps = qps;
        this.countOfReq = countOfReq;
    }

    public TokenDemo processWithTokenBucket() {
        rateLimiter = RateLimiter.create(qps);
        return this;
    }

    //warmupPeriod 是指預熱的時間
    public TokenDemo processWithLeakyBucket() {
        rateLimiter = RateLimiter.create(qps, 00, TimeUnit.MILLISECONDS);
        return this;
    }

    private void processRequest() {
        System.out.println("RateLimiter:" + rateLimiter.getClass());
        long start = System.currentTimeMillis();
        for (int i = 0; i < countOfReq; i++) {
            rateLimiter.acquire();
        }
        long end = System.currentTimeMillis() - start;
        System.out.println("處理請求數量:" + countOfReq + "," +
                "耗時:" + end + "," +
                "qps:" + rateLimiter.getRate() + "," +
                "實際 qps:" + Math.ceil(countOfReq / (end / 1000.00)));
    }

    public void doProcess() throws InterruptedException {
        for (int i = 0; i < 20; i = i + 5) {
            TimeUnit.SECONDS.sleep(i);
            processRequest();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new TokenDemo(50, 100).processWithTokenBucket().doProcess();

        new TokenDemo(50, 100).processWithLeakyBucket().doProcess();
    }
} 

分布式下的限流策略

技術選型
mysql:存儲限流策略的參數等元數據 redis+lua:令牌桶算法實現
具體實現
參考 Redisson 中的令牌桶實現邏輯即可

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市狂票,隨后出現的幾起案子候齿,更是在濱河造成了極大的恐慌,老刑警劉巖闺属,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件慌盯,死亡現場離奇詭異,居然都是意外死亡掂器,警方通過查閱死者的電腦和手機亚皂,發(fā)現死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來国瓮,“玉大人灭必,你說我怎么就攤上這事∧四。” “怎么了禁漓?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長峡懈。 經常有香客問我璃饱,道長,這世上最難降的妖魔是什么肪康? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任荚恶,我火速辦了婚禮撩穿,結果婚禮上,老公的妹妹穿的比我還像新娘谒撼。我一直安慰自己食寡,他們只是感情好,可當我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布廓潜。 她就那樣靜靜地躺著抵皱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪辩蛋。 梳的紋絲不亂的頭發(fā)上呻畸,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機與錄音悼院,去河邊找鬼伤为。 笑死,一個胖子當著我的面吹牛据途,可吹牛的內容都是我干的绞愚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼颖医,長吁一口氣:“原來是場噩夢啊……” “哼位衩!你這毒婦竟也來了?” 一聲冷哼從身側響起熔萧,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤糖驴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后哪痰,有當地人在樹林里發(fā)現了一具尸體遂赠,經...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡久妆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年晌杰,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筷弦。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡肋演,死狀恐怖,靈堂內的尸體忽然破棺而出烂琴,到底是詐尸還是另有隱情爹殊,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布奸绷,位于F島的核電站梗夸,受9級特大地震影響,放射性物質發(fā)生泄漏号醉。R本人自食惡果不足惜反症,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一辛块、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧铅碍,春花似錦润绵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至烦绳,卻和暖如春卿捎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背径密。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工娇澎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人睹晒。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓趟庄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親伪很。 傳聞我的和親對象是個殘疾皇子戚啥,可洞房花燭夜當晚...
    茶點故事閱讀 44,779評論 2 354