沒有預熱,不叫高併發「限流算法第三把法器:令牌桶算法」- 第302篇

相關歷史文章(閱讀本文之前,您可能需要先看下之前的系列👇

「定製Spring Boot Admin UI的頁面」- 第298篇

國內最全的Spring Boot系列之三

版本號命名的前世今生- 值得收藏 - 第299篇

「世界上最好的學習法:費曼學習法」

高併發,不怕不怕「限流算法第一把法器:計數器法」 - 第300篇

精度不夠,滑動時間來湊「限流算法第二把法器:滑動時間窗口算法」- 第301篇

 

 

悟纖:師傅,師傅,你尿牀了!

師傅:(瞬間醒來,在牀上一蹦)哪裏哪裏,這可丟大臉了。

 

悟纖:哈哈… 哈哈… 逗你的,逗你的。

師傅:你看看,待會不撕破你衣服,就不叫師傅。

悟纖:師傅,師傅,師傅... 打在我身,痛在你心,師傅這又是何必吶。

師傅:好了,好了,算是怕了你了,說說這麼早,把爲師叫起來,這是要作甚?

悟纖:當然是學習上一節留下的問題了。

師傅:爲師咋就這麼不相信吶,這太陽是打西邊出來了嘛?

悟纖:反正今天沒太陽,你說哪邊就是哪邊。

師傅:不要在皮了,我們還是趕緊來學習一下吧。

 

一、Warm Up緣起

1.1 現象

(1)DB重啓後,瞬間死亡

一個高併發環境下的DB,進程死亡後進行重啓。由於業務處在高峯期間,上游的負載均衡策略發生了重分配。剛剛啓動的DB瞬間接受了1/3的流量,然後load瘋狂飆升,直至再無響應。

原因就是:新啓動的DB,各種Cache並沒有準備完畢,系統狀態與正常運行時截然不同。可能平常1/10的量,就能夠把它帶入死亡。

(2)服務重啓後,訪問異常

另外一個常見的問題是:我的一臺服務器發生了問題,由於負載均衡的作用,剩下的機器立馬承載了這些請求,運行的很好。當服務重新加入集羣時,卻發生了大量高耗時的請求,在請求量高的情況下,甚至大批大批的失敗。

原因:

~ 服務啓動後,jvm並未完全準備完畢,JIT未編譯等。

~ 應用程序使用的各種資源未準備就緒。

~ 負載均衡發生了rebalance。

 

這兩個問題,都是沒有做好預熱,那什麼是預熱吶。

 

1.2 Warm Up

Warm Up,即冷啓動/預熱的方式。當系統長期處於低水位的情況下,流量突然增加時,直接把系統拉昇到高水位可能瞬間把系統壓垮。通過”冷啓動”,讓通過的流量緩慢增加,在一定時間內逐漸增加到閾值上限,給冷系統一個預熱的時間,避免冷系統被壓垮。

 

       對於Warm Up可以通過令牌桶算法進行實現。

 

二、令牌桶算法

令牌桶算法,又稱token bucket。同樣爲了理解該算法,我們來看一下該算法的示意圖:

 

 

首先,我們有一個固定容量的桶,桶裏存放着令牌(token)。桶一開始是空的,token以 一個固定的速率r往桶裏填充,直到達到桶的容量,多餘的令牌將會被丟棄。每當一個請求過來時,就會嘗試從桶裏移除一個令牌,如果沒有令牌的話,請求無法通過。

 

三、令牌桶算法小栗子

3.1 簡易例子

       我們看一個使用Java代碼寫的最簡單的例子:

public class TokenBucket {
    public long timeStamp = System.currentTimeMillis(); // 當前時間
    public long capacity; // 桶的容量
    public long rate; // 令牌放入速度
    public long tokens; // 當前令牌數量

    public boolean grant() {
        long now = System.currentTimeMillis();
        // 先添加令牌
        tokens = Math.min(capacity, tokens + (now - timeStamp) * rate);
        timeStamp = now;
        if (tokens < 1) {
            // 若不到1個令牌,則拒絕
            return false;
        } else {
            // 還有令牌,領取令牌
            tokens -= 1;
            return true;
        }
    }
}

 

說明:

(1)令牌發放:這裏通過時間差來進行發送令牌。

(2)令牌領取:直接使用-1的方式。

(3)滿了丟棄:使用Math.min取最小值,所以最大也就是初始設置的容量。

 

3.2 Google開源工具包Guava限流工具類RateLimiter

Google開源工具包Guava提供了限流工具類RateLimiter,該類基於令牌桶算法實現流量限制,使用十分方便,而且十分高效。

       添加依賴:

<dependency>

         <groupId>com.google.guava</groupId>

         <artifactId>guava</artifactId>

         <!-- forjava -->

         <version>28.2-jre</version>

         <!-- or,for Android: -->

         <!--<version>28.2-android</version> -->

</dependency>

說明:對於23.0(包括23.0)版本之前java版本沒有後綴-jre,框架提供者估計是爲了能夠更好的區分是給什麼平臺使用的吧 -jre(java),-android(安卓應用程序開發)。

       編寫代碼:

public class RateLimiterTest {
    public static void main(String[] args) {

        RateLimiter limiter = RateLimiter.create(1);

        for (int i = 1; i <= 5; i++) {
            double waitTime = limiter.acquire(i);
            System.out.println("acq:"+i+" cutTime=" + new Date()+" waitTime:" + waitTime);
        }
    }
}

   Run一下:

acq:1 cutTime=Wed Feb 26 14:46:36 CST 2020waitTime:0.0

acq:2 cutTime=Wed Feb 26 14:46:37 CST 2020waitTime:0.980988

acq:3 cutTime=Wed Feb 26 14:46:39 CST 2020waitTime:1.992958

acq:4 cutTime=Wed Feb 26 14:46:42 CST 2020waitTime:2.998297

acq:5 cutTime=Wed Feb 26 14:46:46 CST 2020waitTime:3.996815

說明:

(1)通過RateLimiter.create(1);創建一個限流器,參數代表每秒生成的令牌數。令牌的管理RateLimiter類就輕鬆幫我們搞定了。

(2)limiter.acquire(i);來以阻塞的方式獲取令牌,也可以通過tryAcquire(intpermits, long timeout, TimeUnit unit)來設置等待超時時間的方式獲取令牌,如果超timeout爲0,則代表非阻塞,獲取不到立即返回。

 

四、悟纖小結

師傅:爲師今天講了不少知識點,有點口乾舌燥了,剩下的時間給你了。

悟纖:師傅,您休息休息,請放心把舞臺交到我手中。

悟纖:來,來來,music響起來。

      

要記住幾點:

(1)Warm Up(冷啓動/預熱):通過”冷啓動”,讓通過的流量緩慢增加,在一定時間內逐漸增加到閾值上限,給冷系統一個預熱的時間,避免冷系統被壓垮。

(2)Warm Up相應的實現算法是令牌桶算法。

(3)令牌桶算法簡單理解就是由一個桶,桶裏有令牌,也就是token,要請求前先從桶裏拿一下令牌,如果拿到領牌,則可以訪問資源,如果拿不到令牌,則拒絕訪問;另外就是會根據一定的速率往桶裏放入令牌。

 

我就是我,是顏色不一樣的煙火。
我就是我,是與衆不同的小蘋果。

學院中有Spring Boot相關的課程:

à悟空學院:https://t.cn/Rg3fKJD

SpringBoot視頻:http://t.cn/A6ZagYTi

Spring Cloud視頻:http://t.cn/A6ZagxSR

SpringBoot Shiro視頻:http://t.cn/A6Zag7IV

SpringBoot交流平臺:https://t.cn/R3QDhU0

SpringData和JPA視頻:http://t.cn/A6Zad1OH

SpringSecurity5.0視頻:http://t.cn/A6ZadMBe

Sharding-JDBC分庫分表實戰:http://t.cn/A6ZarrqS

分佈式事務解決方案「手寫代碼」:http://t.cn/A6ZaBnIr

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章