自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

來,四種分布式限流算法實(shí)現(xiàn)!

開發(fā) 前端
關(guān)于Redission是怎么實(shí)現(xiàn)這個(gè)限速器的,大家可以看一下參考[3],還是Redisson家的老傳統(tǒng)——Lua腳本,設(shè)計(jì)相當(dāng)巧妙。

大家好,我是老三,最近公司在搞年終大促,隨著各種營銷活動(dòng)“組合拳”打出,進(jìn)站流量時(shí)不時(shí)會(huì)有一個(gè)小波峰,一般情況下,當(dāng)然是流量越多越好,前提是系統(tǒng)能杠地住。大家都知道,一個(gè)分布式系統(tǒng),有兩個(gè)“棄車保帥”的策略:限流和熔斷,這期,我們就來討論一下分布式系統(tǒng)的限流。

探探限流

帶著問題走近限流

為什么要限流呢?

就像我上面說的,流量多,的確是一件好事,但是如果過載,把系統(tǒng)打掛了,那大家都要吃席了。

沒逝吧

所以,在各種大促活動(dòng)之前,要對(duì)系統(tǒng)進(jìn)行壓測,評(píng)估整個(gè)系統(tǒng)的峰值QPS,要做一些限流的設(shè)置,超過一定閾值,就拒絕處理或者延后處理,避免把系統(tǒng)打掛的情況出現(xiàn)。

限流和熔斷有什么區(qū)別?

限流發(fā)生在流量進(jìn)來之前,超過的流量進(jìn)行限制。

熔斷是一種應(yīng)對(duì)故障的機(jī)制,發(fā)生在流量進(jìn)來之后,如果系統(tǒng)發(fā)生故障或者異常,熔斷會(huì)自動(dòng)切斷請(qǐng)求,防止故障進(jìn)一步擴(kuò)展,導(dǎo)致服務(wù)雪崩。

限流和削峰有什么區(qū)別?

削峰是對(duì)流量的平滑處理,通過緩慢地增加請(qǐng)求的處理速率來避免系統(tǒng)瞬時(shí)過載。

削峰大概就是水庫,把流量儲(chǔ)存起來,慢慢流,限流大概就是閘口,拒絕超出的流量。

限流的通用流程

那么具體限流怎么實(shí)現(xiàn)呢?可以概括為以下幾個(gè)步驟:

限流通用流程限流通用流程

  1. 統(tǒng)計(jì)請(qǐng)求流量:記錄請(qǐng)求的數(shù)量或速率,可以通過計(jì)數(shù)器、滑動(dòng)窗口等方式進(jìn)行統(tǒng)計(jì)。
  2. 判斷是否超過限制:根據(jù)設(shè)定的限制條件,判斷當(dāng)前請(qǐng)求流量是否超過限制。
  3. 執(zhí)行限流策略:如果請(qǐng)求流量超過限制,執(zhí)行限流策略,如拒絕請(qǐng)求、延遲處理、返回錯(cuò)誤信息等。
  4. 更新統(tǒng)計(jì)信息:根據(jù)請(qǐng)求的處理結(jié)果,更新統(tǒng)計(jì)信息,如增加計(jì)數(shù)器的值、更新滑動(dòng)窗口的數(shù)據(jù)等。
  5. 重復(fù)執(zhí)行以上步驟:不斷地統(tǒng)計(jì)請(qǐng)求流量、判斷是否超過限制、執(zhí)行限流策略、更新統(tǒng)計(jì)信息

需要注意的是,具體的限流算法實(shí)現(xiàn)可能會(huì)根據(jù)不同的場景和需求進(jìn)行調(diào)整和優(yōu)化,比如使用令牌桶算法、漏桶算法等。

單機(jī)限流和分布式限流

我們注意到,在限流的通用流程里,需要統(tǒng)計(jì)請(qǐng)求量、更新統(tǒng)計(jì)量,那么這個(gè)請(qǐng)求量的統(tǒng)計(jì)和更新就必須維護(hù)在一個(gè)存儲(chǔ)里。

假如只是一個(gè)單機(jī)版的環(huán)境,那就很好辦了,直接儲(chǔ)存到本地。

單機(jī)vs集群單機(jī)vs集群

但是一般來講,我們的服務(wù)都是集群部署的,如何來實(shí)現(xiàn)多臺(tái)機(jī)器之間整體的限流呢?

這時(shí)候就可以把我們的統(tǒng)計(jì)信息放到Tair或Redis等分布式的K-V存儲(chǔ)中。

四種限流算法與分布式實(shí)現(xiàn)

接下來,我們開始實(shí)現(xiàn)一些常見的限流算法,這里使用Redis作為分布式存儲(chǔ),Redis不用多說了吧,最流行的分布式緩存DB;Redission作為Redis客戶端,Redission單純只是用來做分布式鎖,有些”屈才“,其實(shí)用來作為Redis的客戶端也非常好用。

五種限流算法分布式實(shí)現(xiàn)

在開始之前,我們先簡單準(zhǔn)備一下環(huán)境,Redis安裝和項(xiàng)目創(chuàng)建就不多說了。

  • 添加依賴
<dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.16.2</version>
        </dependency>
  • 用單例模式獲取RedissonClient,這里就不注冊成bean了,跑單測太慢
public class RedissonConfig {

    private static final String REDIS_ADDRESS = "redis://127.0.0.1:6379";

    private static volatile  RedissonClient redissonClient;

   public static RedissonClient getInstance(){
        if (redissnotallow==null){
            synchronized (RedissonConfig.class){
                if (redissnotallow==null){
                    Config config = new Config();
                    config.useSingleServer().setAddress(REDIS_ADDRESS);
                    redissonClient = Redisson.create(config);
                    return redissonClient;
                }
            }
        }
        return redissonClient;
    }
}

固定窗口限流算法

算法原理

固定窗口算法,很多參考資料也稱之為計(jì)數(shù)器算法,當(dāng)然我個(gè)人理解,計(jì)數(shù)器算法是固定窗口算法的一種特例,當(dāng)然我們不糾結(jié)那么多。

固定窗口算法,是一種比較簡單的限流算法,它把時(shí)間劃分為固定的時(shí)間窗口,每個(gè)窗口內(nèi)允許的請(qǐng)求次數(shù)設(shè)置限制。如果在一個(gè)時(shí)間窗口內(nèi),請(qǐng)求次數(shù)超過了上限,那么就會(huì)觸發(fā)限流。

在這里插入圖片描述

算法實(shí)現(xiàn)

基于Redisson的實(shí)現(xiàn)固定窗口相當(dāng)簡單。在每個(gè)窗口期內(nèi),我們可以通過incrementAndGet操作來統(tǒng)計(jì)請(qǐng)求的數(shù)量。一旦窗口期結(jié)束,我們可以利用Redis的鍵過期功能來自動(dòng)重置計(jì)數(shù)。

  • 來看下代碼實(shí)現(xiàn):
public class FixedWindowRateLimiter {
    public static final String KEY = "fixedWindowRateLimiter:";
    /**
     * 請(qǐng)求限制數(shù)量
     */
    private Long limit;
    /**
     * 窗口大?。▎挝唬篠)
     */
    private Long windowSize;

    public FixedWindowRateLimiter(Long limit, Long windowSize) {
        this.limit = limit;
        this.windowSize = windowSize;
    }

    /**
     * 固定窗口限流
     */
    public boolean triggerLimit(String path) {
        RedissonClient redissonClient = RedissonConfig.getInstance();
        //加分布式鎖,防止并發(fā)情況下窗口初始化時(shí)間不一致問題
        RLock rLock = redissonClient.getLock(KEY + "LOCK:" + path);
        try {
            rLock.lock(100, TimeUnit.MILLISECONDS);
            String redisKey = KEY + path;
            RAtomicLong counter = redissonClient.getAtomicLong(redisKey);
            //計(jì)數(shù)
            long count = counter.incrementAndGet();
            //如果為1的話,就說明窗口剛初始化
            if (count == 1) {
                //直接設(shè)置過期時(shí)間,作為窗口
                counter.expire(windowSize, TimeUnit.SECONDS);
            }
            //觸發(fā)限流
            if (count > limit) {
                //觸發(fā)限流的不記在請(qǐng)求數(shù)量中
                counter.decrementAndGet();
                return true;
            }
            return false;
        } finally {
            rLock.unlock();
        }
    }

}

這里還額外用了一個(gè)分布式鎖,來解決并發(fā)情況下,窗口的初始化問題。

  • 再來測試一下
class FixedWindowRateLimiterTest {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(20, 50, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10));

    @Test
    @DisplayName("1min限制10次請(qǐng)求固定窗口測試")
    void triggerLimit() throws InterruptedException {
        FixedWindowRateLimiter fixedWindowRateLimiter = new FixedWindowRateLimiter(10L,60L);
        //模擬不同窗口內(nèi)的調(diào)用
        for (int i = 0; i < 3; i++) {
            CountDownLatch countDownLatch = new CountDownLatch(20);
            //20個(gè)線程并發(fā)調(diào)用
            for (int j = 0; j < 20; j++) {
                threadPoolExecutor.execute(() -> {
                    boolean isLimit = fixedWindowRateLimiter.triggerLimit("/test");
                    System.out.println(isLimit);
                    countDownLatch.countDown();
                });
            }
            countDownLatch.await();
            //休眠1min
            TimeUnit.MINUTES.sleep(1);
        }
    }
}

當(dāng)然大家也可以寫個(gè)接口,用Jmeter之類的壓測工具來進(jìn)行測試。

固定窗口算法的優(yōu)點(diǎn)是實(shí)現(xiàn)簡單,占用空間小,但是它存在臨界問題,由于窗口的切換是瞬間完成的,因此請(qǐng)求的處理并不平滑,可能會(huì)在窗口切換的瞬間出現(xiàn)流量的劇烈波動(dòng)。

比如這個(gè)例子,假如在00:02,突然有大量請(qǐng)求過來,但是我們這時(shí)候計(jì)數(shù)重置了,那么就沒法限制突發(fā)的這些流量。

臨界值問題

滑動(dòng)窗口算法

為了緩解固定窗口的突發(fā)流量問題,可以采用滑動(dòng)窗口算法,計(jì)算機(jī)網(wǎng)絡(luò)中TCP的流量控制就是采用滑動(dòng)窗口算法。

算法原理

滑動(dòng)窗口限流算法的原理是將一個(gè)大的時(shí)間窗口劃分為多個(gè)小的時(shí)間窗口,每個(gè)小的窗口都有獨(dú)立的計(jì)數(shù)。

請(qǐng)求過來的時(shí)候,判斷請(qǐng)求的次數(shù)是否超過整個(gè)窗口的限制。窗口的移動(dòng)是每次向前滑動(dòng)一個(gè)小的單元窗口。

例如下面這個(gè)滑動(dòng)窗口,將大時(shí)間窗口1min分成了5個(gè)小窗口,每個(gè)小窗口的時(shí)間是12s。

每個(gè)單元格有自己獨(dú)立的計(jì)數(shù)器,每過12s就會(huì)向前移動(dòng)一格。

假如有請(qǐng)求在00:01的時(shí)候過來,這時(shí)候窗口的計(jì)數(shù)就是3+12+9+15=39,也能起到限流的作用。

滑動(dòng)窗口算法示意圖

這就是為什么滑動(dòng)窗口能解決臨界問題,滑的格子越多,那么整體的滑動(dòng)就會(huì)越平滑,限流的效果就會(huì)越精準(zhǔn)。

算法實(shí)現(xiàn)

那么我們這里怎么實(shí)現(xiàn)滑動(dòng)窗口限流算法呢?非常簡單,我們可以直接使用Redis的有序集合(zset)結(jié)構(gòu)。

我們使用時(shí)間戳作為score和member,有請(qǐng)求過來的時(shí)候,就把當(dāng)前時(shí)間戳添加到有序集合里。那么窗口之外的請(qǐng)求,我們可以根據(jù)窗口大小,計(jì)算出起始時(shí)間戳,刪除窗口外的請(qǐng)求。這樣,有序集合的大小,就是我們這個(gè)窗口的請(qǐng)求數(shù)了。

zset實(shí)現(xiàn)滑動(dòng)窗口

  • 代碼實(shí)現(xiàn)
public class SlidingWindowRateLimiter {
    public static final String KEY = "slidingWindowRateLimiter:";

    /**
     * 請(qǐng)求次數(shù)限制
     */
    private Long limit;
    /**
     * 窗口大?。▎挝唬篠)
     */
    private Long windowSize;

    public SlidingWindowRateLimiter(Long limit, Long windowSize) {
        this.limit = limit;
        this.windowSize = windowSize;
    }


    public boolean triggerLimit(String path) {
        RedissonClient redissonClient = RedissonConfig.getInstance();
        //窗口計(jì)數(shù)
        RScoredSortedSet<Long> counter = redissonClient.getScoredSortedSet(KEY + path);
        //使用分布式鎖,避免并發(fā)設(shè)置初始值的時(shí)候,導(dǎo)致窗口計(jì)數(shù)被覆蓋
        RLock rLock = redissonClient.getLock(KEY + "LOCK:" + path);
        try {
            rLock.lock(200, TimeUnit.MILLISECONDS);
            // 當(dāng)前時(shí)間戳
            long currentTimestamp = System.currentTimeMillis();
            // 窗口起始時(shí)間戳
            long windowStartTimestamp = currentTimestamp - windowSize * 1000;
            // 移除窗口外的時(shí)間戳,左閉右開
            counter.removeRangeByScore(0, true, windowStartTimestamp, false);
            // 將當(dāng)前時(shí)間戳作為score,也作為member,
            // TODO:高并發(fā)情況下可能沒法保證唯一,可以加一個(gè)唯一標(biāo)識(shí)
            counter.add(currentTimestamp, currentTimestamp);
            //使用zset的元素個(gè)數(shù),作為請(qǐng)求計(jì)數(shù)
            long count = counter.size();
            // 判斷時(shí)間戳數(shù)量是否超過限流閾值
            if (count > limit) {
                System.out.println("[triggerLimit] path:" + path + " count:" + count + " over limit:" + limit);
                return true;
            }
            return false;
        } finally {
            rLock.unlock();
        }
    }

}

這里還有一個(gè)小的可以完善的點(diǎn),zset在member相同的情況下,是會(huì)覆蓋的,也就是說高并發(fā)情況下,時(shí)間戳可能會(huì)重復(fù),那么就有可能統(tǒng)計(jì)的請(qǐng)求偏少,這里可以用時(shí)間戳+隨機(jī)數(shù)來緩解,也可以生成唯一序列來解決,比如UUID、雪花算法等等。

  • 還是來測試一下
class SlidingWindowRateLimiterTest {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(30, 50, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10));

    @Test
    @DisplayName("滑動(dòng)窗口限流")
    void triggerLimit() throws InterruptedException {
        SlidingWindowRateLimiter slidingWindowRateLimiter = new SlidingWindowRateLimiter(10L, 1L);
        //模擬在不同時(shí)間片內(nèi)的請(qǐng)求
        for (int i = 0; i < 8; i++) {
            CountDownLatch countDownLatch = new CountDownLatch(20);
            for (int j = 0; j < 20; j++) {
                threadPoolExecutor.execute(() -> {
                    boolean isLimit = slidingWindowRateLimiter.triggerLimit("/test");
                    System.out.println(isLimit);
                    countDownLatch.countDown();
                });
            }
            countDownLatch.await();
            //休眠10s
            TimeUnit.SECONDS.sleep(10L);
        }
    }
}

用Redis實(shí)現(xiàn)了滑動(dòng)窗口限流,解決了固定窗口限流的邊界問題,當(dāng)然這里也帶來了新的問題,因?yàn)槲覀兇鎯?chǔ)了窗口期的所有請(qǐng)求,所以高并發(fā)的情況下,可能會(huì)比較占內(nèi)存。

漏桶算法

我們可以看到,計(jì)數(shù)器類的限流,體現(xiàn)的是一個(gè)“戛然而止”,超過限制,立馬決絕,但是有時(shí)候,我們可能只是希望請(qǐng)求平滑一些,追求的是“波瀾不驚”,這時(shí)候就可以考慮使用其它的限流算法。

算法原理

漏桶算法(Leaky Bucket),名副其實(shí),就是請(qǐng)求就像水一樣以任意速度注入漏桶,而桶會(huì)按照固定的速率將水漏掉。

漏桶算法

當(dāng)進(jìn)水速率大于出水速率的時(shí)候,漏桶會(huì)變滿,此時(shí)新進(jìn)入的請(qǐng)求將會(huì)被丟棄。

漏桶算法的兩大作用是網(wǎng)絡(luò)流量整形(Traffic Shaping)和速度限制(Rate Limiting)。

算法實(shí)現(xiàn)

我們接著看看具體應(yīng)該怎么實(shí)現(xiàn)。

在滑動(dòng)窗口限流算法里我們用到了RScoredSortedSet,非常好用對(duì)不對(duì),這里也可以用這個(gè)結(jié)構(gòu),直接使用ZREMRANGEBYSCORE命令來刪除舊的請(qǐng)求。

進(jìn)水就不用多說了,請(qǐng)求進(jìn)來,判斷桶有沒有滿,滿了就拒絕,沒滿就往桶里丟請(qǐng)求。

那么出水怎么辦呢?得保證穩(wěn)定速率出水,可以用一個(gè)定時(shí)任務(wù),來定時(shí)去刪除舊的請(qǐng)求。

  • 代碼實(shí)現(xiàn)
public class LeakyBucketRateLimiter {
    private RedissonClient redissonClient = RedissonConfig.getInstance();
    private static final String KEY_PREFIX = "LeakyBucket:";

    /**
     * 桶的大小
     */
    private Long bucketSize;
    /**
     * 漏水速率,單位:個(gè)/秒
     */
    private Long leakRate;


    public LeakyBucketRateLimiter(Long bucketSize, Long leakRate) {
        this.bucketSize = bucketSize;
        this.leakRate = leakRate;
        //這里啟動(dòng)一個(gè)定時(shí)任務(wù),每s執(zhí)行一次
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
        executorService.scheduleAtFixedRate(this::leakWater, 0, 1, TimeUnit.SECONDS);
    }

    /**
     * 漏水
     */
    public void leakWater() {
        RSet<String> pathSet=redissonClient.getSet(KEY_PREFIX+":pathSet");
        //遍歷所有path,刪除舊請(qǐng)求
        for(String path:pathSet){
            String redisKey = KEY_PREFIX + path;
            RScoredSortedSet<Long> bucket = redissonClient.getScoredSortedSet(KEY_PREFIX + path);
            // 獲取當(dāng)前時(shí)間
            long now = System.currentTimeMillis();
            // 刪除舊的請(qǐng)求
            bucket.removeRangeByScore(0, true,now - 1000 * leakRate,true);
        }
    }

    /**
     * 限流
     */
    public boolean triggerLimit(String path) {
        //加鎖,防止并發(fā)初始化問題
        RLock rLock = redissonClient.getLock(KEY_PREFIX + "LOCK:" + path);
        try {
            rLock.lock(100,TimeUnit.MILLISECONDS);
            String redisKey = KEY_PREFIX + path;
            RScoredSortedSet<Long> bucket = redissonClient.getScoredSortedSet(redisKey);
            //這里用一個(gè)set,來存儲(chǔ)所有path
            RSet<String> pathSet=redissonClient.getSet(KEY_PREFIX+":pathSet");
            pathSet.add(path);
            // 獲取當(dāng)前時(shí)間
            long now = System.currentTimeMillis();
            // 檢查桶是否已滿
            if (bucket.size() < bucketSize) {
                // 桶未滿,添加一個(gè)元素到桶中
                bucket.add(now,now);
                return false;
            }
            // 桶已滿,觸發(fā)限流
            System.out.println("[triggerLimit] path:"+path+" bucket size:"+bucket.size());
            return true;
        }finally {
            rLock.unlock();
        }
    }
    
}

在代碼實(shí)現(xiàn)里,我們用了RSet來存儲(chǔ)path,這樣一來,一個(gè)定時(shí)任務(wù),就可以搞定所有path對(duì)應(yīng)的桶的出水,而不用每個(gè)桶都創(chuàng)建一個(gè)一個(gè)定時(shí)任務(wù)。

這里我直接用ScheduledExecutorService啟動(dòng)了一個(gè)定時(shí)任務(wù),1s跑一次,當(dāng)然集群環(huán)境下,每臺(tái)機(jī)器都跑一個(gè)定時(shí)任務(wù),對(duì)性能是極大的浪費(fèi),而且不好管理,我們可以用分布式定時(shí)任務(wù),比如xxl-job去執(zhí)行l(wèi)eakWater。

  • 最后還是大家熟悉的測試
class LeakyBucketRateLimiterTest {

    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(30, 50, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10));

    @Test
    @DisplayName("漏桶算法")
    void triggerLimit() throws InterruptedException {
        LeakyBucketRateLimiter leakyBucketRateLimiter = new LeakyBucketRateLimiter(10L, 1L);
        for (int i = 0; i < 8; i++) {
            CountDownLatch countDownLatch = new CountDownLatch(20);
            for (int j = 0; j < 20; j++) {
                threadPoolExecutor.execute(() -> {
                    boolean isLimit = leakyBucketRateLimiter.triggerLimit("/test");
                    System.out.println(isLimit);
                    countDownLatch.countDown();
                });
            }
            countDownLatch.await();
            //休眠10s
            TimeUnit.SECONDS.sleep(10L);
        }
    }
}

漏桶算法能夠有效防止網(wǎng)絡(luò)擁塞,實(shí)現(xiàn)也比較簡單。

但是,因?yàn)槁┩暗某鏊俾适枪潭ǖ模偃缤蝗粊砹舜罅康恼?qǐng)求,那么只能丟棄超量的請(qǐng)求,即使下游能處理更大的流量,沒法充分利用系統(tǒng)資源。

令牌桶算法

令牌桶算法來了!

算法原理

令牌桶算法是對(duì)漏桶算法的一種改進(jìn)。

它的主要思想是:系統(tǒng)以一種固定的速率向桶中添加令牌,每個(gè)請(qǐng)求在發(fā)送前都需要從桶中取出一個(gè)令牌,只有取到令牌的請(qǐng)求才被通過。因此,令牌桶算法允許請(qǐng)求以任意速率發(fā)送,只要桶中有足夠的令牌。

令牌桶算法令牌桶算法

算法實(shí)現(xiàn)

我們繼續(xù)看怎么實(shí)現(xiàn),首先是要發(fā)放令牌,要固定速率,那我們又得開個(gè)線程,定時(shí)往桶里投令牌,然后……

——然后Redission提供了令牌桶算法的實(shí)現(xiàn),舒不舒服?

拿來吧你

拿來就用!

  • 代碼實(shí)現(xiàn)
public class TokenBucketRateLimiter {

    public static final String KEY = "TokenBucketRateLimiter:";

    /**
     * 閾值
     */
    private Long limit;
    /**
     * 添加令牌的速率,單位:個(gè)/秒
     */
    private Long tokenRate;

    public TokenBucketRateLimiter(Long limit, Long tokenRate) {
        this.limit = limit;
        this.tokenRate = tokenRate;
    }

    /**
     * 限流算法
     */
    public boolean triggerLimit(String path){
        RedissonClient redissnotallow=RedissonConfig.getInstance();
        RRateLimiter rateLimiter = redissonClient.getRateLimiter(KEY+path);
        // 初始化,設(shè)置速率模式,速率,間隔,間隔單位
        rateLimiter.trySetRate(RateType.OVERALL, limit, tokenRate, RateIntervalUnit.SECONDS);
        // 獲取令牌
        return rateLimiter.tryAcquire();
    }
}

Redisson實(shí)現(xiàn)的,還是比較穩(wěn)的,這里就不測試了。

關(guān)于Redission是怎么實(shí)現(xiàn)這個(gè)限速器的,大家可以看一下參考[3],還是Redisson家的老傳統(tǒng)——Lua腳本,設(shè)計(jì)相當(dāng)巧妙。

總結(jié)

在這篇文章里,我們對(duì)四(三)種限流算法進(jìn)行了分布式實(shí)現(xiàn),采用了非常好用的Redission客戶端,當(dāng)然我們也有不完善的地方:

  • 并發(fā)處理采用了分布式鎖,高并發(fā)情況下,對(duì)性能有一定損耗,邏輯最好還是直接采用Lua腳本實(shí)現(xiàn),來提高性能
  • 可以提供更加優(yōu)雅的調(diào)用方式,比如利用aop實(shí)現(xiàn)注解式調(diào)用,代碼設(shè)計(jì)也可以更加優(yōu)雅,繼承體系可以完善一下
  • 沒有實(shí)現(xiàn)限流的拒絕策略,比如拋異常、緩存、丟進(jìn)MQ打散……限流是一種方法,最終的目的還是盡可能保證系統(tǒng)平穩(wěn)

如果后面有機(jī)會(huì),希望可以繼續(xù)完善這個(gè)簡單的Demo,達(dá)到工程級(jí)的應(yīng)用。

除此之外,市面上也有很多好用的開源限流工具:

  • Guava RateLimiter ,基于令牌桶算法限流,當(dāng)然是單機(jī)的;
  • Sentinel ,基于滑動(dòng)窗口限流,支持單機(jī),也支持集群
  • 網(wǎng)關(guān)限流,很多網(wǎng)關(guān)自帶限流方法,比如Spring Cloud Gateway、Nginx

……

好了,這期文章就到這里了,我們下期見。

參考:

[1]. 面試官:來,年輕人!請(qǐng)手?jǐn)]5種常見限流算法!

[2].https://zhuanlan.zhihu.com/p/479956069

[3].https://github.com/oneone1995/blog/issues/13

責(zé)任編輯:武曉燕 來源: 三分惡
相關(guān)推薦

2024-02-28 09:22:03

限流算法數(shù)量

2023-11-15 07:40:40

2021-03-04 17:55:27

算法Raft分布式

2020-05-19 22:05:39

Serverless微服務(wù)分布式

2015-03-19 15:13:20

PHP基本排序算法代碼實(shí)現(xiàn)

2023-09-13 09:52:14

分布式鎖Java

2018-07-16 08:29:54

redis集群限流

2014-05-08 14:38:26

tornadoredissession

2024-04-08 11:04:03

2022-01-12 12:46:32

Go限流保障

2021-06-24 17:55:40

Python 開發(fā)編程語言

2011-03-16 09:05:53

NATiptables

2021-12-22 09:34:01

Golagn配置方式

2021-08-11 20:17:22

推薦算法系統(tǒng)

2022-06-27 08:21:05

Seata分布式事務(wù)微服務(wù)

2018-06-11 11:12:09

秒殺限流分布式

2018-06-19 09:35:51

分布式系統(tǒng)限流

2019-08-14 11:08:01

數(shù)據(jù)庫場景選型

2009-09-08 17:20:01

C#排序算法

2010-08-05 09:33:08

Flex頁面跳轉(zhuǎn)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)