最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Redisson分布式限流器RRateLimiter的使用及原理小結(jié)

 更新時間:2024年06月27日 09:14:16   作者:呦,又寫B(tài)UG呢  
本文主要介紹了Redisson分布式限流器RRateLimiter的使用及原理小結(jié),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

一、基本使用

1.1 創(chuàng)建限流器

/**
 * Returns rate limiter instance by name
 * 
 * @param name of rate limiter
 * @return RateLimiter object
 */
RRateLimiter getRateLimiter(String name);
/**
 * Initializes RateLimiter's state and stores config to Redis server.
 * 
 * @param mode - rate mode
 * @param rate - rate
 * @param rateInterval - rate time interval
 * @param rateIntervalUnit - rate time interval unit
 * @return true if rate was set and false otherwise
 */
boolean trySetRate(RateType mode, long rate, long rateInterval, RateIntervalUnit rateIntervalUnit);

trySetRate 用于設(shè)置限流參數(shù)。其中 RateType 包含 OVERALL 和 PER_CLIENT 兩個枚舉常量,分別表示全局限流和單機限流。后面三個參數(shù)表明了令牌的生成速率,即每 rateInterval 生成 rate 個令牌,rateIntervalUnit 為 rateInterval 的時間單位。

1.2 獲取令牌

/**
 * Acquires a specified permits from this RateLimiter, 
 * blocking until one is available.
 *
 * Acquires the given number of permits, if they are available 
 * and returns immediately, reducing the number of available permits 
 * by the given amount.
 * 
 * @param permits the number of permits to acquire
 */
void acquire(long permits);

/**
 * Acquires the given number of permits only if all are available
 * within the given waiting time.
 *
 * Acquires the given number of permits, if all are available and returns immediately,
 * with the value true, reducing the number of available permits by one.
 *
 * If no permit is available then the current thread becomes
 * disabled for thread scheduling purposes and lies dormant until
 * the specified waiting time elapses.
 *
 * If a permits is acquired then the value true is returned.
 *
 * If the specified waiting time elapses then the value false
 * is returned.  If the time is less than or equal to zero, the method
 * will not wait at all.
 *
 * @param permits amount
 * @param timeout the maximum time to wait for a permit
 * @param unit the time unit of the timeout argument
 * @return true if a permit was acquired and false
 *         if the waiting time elapsed before a permit was acquired
 */
boolean tryAcquire(long permits, long timeout, TimeUnit unit);

acquire 和 tryAcquire 均可用于獲取指定數(shù)量的令牌,不過 acquire 會阻塞等待,而 tryAcquire 會等待 timeout 時間,如果仍然沒有獲得指定數(shù)量的令牌直接返回 false。

1.3 使用示例

@Slf4j
@SpringBootTest
class RateLimiterTest {
    
    @Autowired
    private RedissonClient redissonClient;
    
    private static final int threadCount = 10;

    @Test
    void test() throws InterruptedException {
        RRateLimiter rateLimiter = redissonClient.getRateLimiter("my_limiter");
        rateLimiter.trySetRate(RateType.OVERALL, 10, 1, RateIntervalUnit.SECONDS);

        CountDownLatch latch = new CountDownLatch(threadCount);

        for (int i = 0; i < threadCount; i++) {
            new Thread(() -> {
                rateLimiter.tryAcquire(5, 3, TimeUnit.SECONDS);
                latch.countDown();
                log.info("latch count {}", latch.getCount());
            }).start();
        }
        
        latch.await();
    }
}

2024-01-16 20:14:27 INFO  [Thread-2] atreus.ink.rate.RateLimiterTest : latch count 9
2024-01-16 20:14:27 INFO  [Thread-3] atreus.ink.rate.RateLimiterTest : latch count 8
2024-01-16 20:14:28 INFO  [Thread-1] atreus.ink.rate.RateLimiterTest : latch count 7
2024-01-16 20:14:29 INFO  [Thread-10] atreus.ink.rate.RateLimiterTest : latch count 6
2024-01-16 20:14:29 INFO  [Thread-8] atreus.ink.rate.RateLimiterTest : latch count 5
2024-01-16 20:14:30 INFO  [Thread-5] atreus.ink.rate.RateLimiterTest : latch count 4
2024-01-16 20:14:30 INFO  [Thread-4] atreus.ink.rate.RateLimiterTest : latch count 3
2024-01-16 20:14:30 INFO  [Thread-6] atreus.ink.rate.RateLimiterTest : latch count 2
2024-01-16 20:14:30 INFO  [Thread-7] atreus.ink.rate.RateLimiterTest : latch count 1
2024-01-16 20:14:30 INFO  [Thread-9] atreus.ink.rate.RateLimiterTest : latch count 0

二、實現(xiàn)原理

Redisson 的 RRateLimiter 基于令牌桶實現(xiàn),令牌桶的主要特點如下:

  • 令牌以固定速率生成。
  • 生成的令牌放入令牌桶中存放,如果令牌桶滿了則多余的令牌會直接丟棄,當請求到達時,會嘗試從令牌桶中取令牌,取到了令牌的請求可以執(zhí)行。
  • 如果桶空了,那么嘗試取令牌的請求會被直接丟棄。

RRateLimiter 在創(chuàng)建限流器時通過下面 Lua 腳本設(shè)置限流器的相關(guān)參數(shù):

redis.call('hsetnx', KEYS[1], 'rate', ARGV[1]);
redis.call('hsetnx', KEYS[1], 'interval', ARGV[2]);
return redis.call('hsetnx', KEYS[1], 'type', ARGV[3]);

而獲取令牌則是通過以下的 Lua 腳本實現(xiàn):

-- 請求參數(shù)示例
-- KEYS[1] my_limiter
-- KEYS[2] {my_limiter}:value
-- KEYS[4] {my_limiter}:permits
-- ARGV[1] 3 本次請求的令牌數(shù)
-- ARGV[2] 1705396021850 System.currentTimeMillis()
-- ARGV[3] 6966135962453115904 ThreadLocalRandom.current().nextLong()

-- 讀取 RRateLimiter.trySetRate 中配置的限流器信息
local rate = redis.call('hget', KEYS[1], 'rate');  -- 10 一個時間窗口內(nèi)產(chǎn)生的令牌數(shù)
local interval = redis.call('hget', KEYS[1], 'interval');  -- 1000 一個時間窗口對應的毫秒數(shù)
local type = redis.call('hget', KEYS[1], 'type');  -- 0 全局限流
assert(rate ~= false and interval ~= false and type ~= false, 'RateLimiter is not initialized')

local valueName = KEYS[2];  -- {my_limiter}:value 當前可用令牌數(shù)字符串的 key
local permitsName = KEYS[4];  -- {my_limiter}:permits 授權(quán)記錄有序集合的 key

-- 單機限流配置 無需考慮
if type == '1' then
    valueName = KEYS[3];
    permitsName = KEYS[5];
end;

-- 查詢當前可用的令牌數(shù) 查詢失敗表明是首次請求令牌
local currentValue = redis.call('get', valueName);
if currentValue == false then -- 首次請求令牌
    -- 單次請求的令牌數(shù)不能超過一個時間窗口內(nèi)產(chǎn)生的令牌數(shù)
    assert(tonumber(rate) >= tonumber(ARGV[1]), 'Requested permits amount could not exceed defined rate');
    
    -- 更新當前可用令牌數(shù)以及令牌授權(quán)記錄 {my_limiter}:permits
    -- set {my_limiter}:permits 10
    redis.call('set', valueName, rate);
    -- zadd {my_limiter}:permits 1705396021850 6966135962453115904_1
    redis.call('zadd', permitsName, ARGV[2], struct.pack('fI', ARGV[3], ARGV[1]));
    -- decrby {my_limiter}:permits 3
    redis.call('decrby', valueName, ARGV[1]);
    return nil;
else -- 再次請求令牌
    -- 查詢可以回收的令牌對應的授權(quán)記錄 即一個時間窗口前的所有授權(quán)記錄且包括一個時間窗口前這一時刻
    -- 舊令牌回收的本質(zhì)是新令牌的加入 如果一個令牌是在一個時間窗口前被分配的 那經(jīng)過一個時間窗口后這個空出的位置應該已經(jīng)由新令牌填充
    -- zrangebyscore {my_limiter}:permits 0 1705396020850
    local expiredValues = redis.call('zrangebyscore', permitsName, 0, tonumber(ARGV[2]) - interval); -- [1936135962853113704_2, 536135765023123704_5]
    
    -- 統(tǒng)計可以回收的令牌數(shù)
    local released = 0;
    for i, v in ipairs(expiredValues) do
        local random, permits = struct.unpack('fI', v);
        -- released = released + 2
        -- released = released + 5
        released = released + permits;
    end;

    -- 刪除授權(quán)記錄并回收令牌
    if released > 0 then
        -- zrem {my_limiter}:permits 1936135962853113704_2 536135765023123704_5
        redis.call('zrem', permitsName, unpack(expiredValues));
        currentValue = tonumber(currentValue) + released;
        -- incrby {my_limiter}:value 7
        redis.call('set', valueName, currentValue);
    end;

    if tonumber(currentValue) < tonumber(ARGV[1]) then
        -- 如果回收后可用令牌數(shù)仍然不足 返回需要等待的時間
        -- zrangebyscore {my_limiter}:permits (1705396020850 1705396021850 withscores limit 0 1
        local nearest = redis.call('zrangebyscore', permitsName, '(' .. (tonumber(ARGV[2]) - interval), tonumber(ARGV[2]), 'withscores', 'limit', 0, 1);
        local random, permits = struct.unpack('fI', nearest[1]);
        -- 1705396021650 - 1705396021850 + 1000 = 800
        return tonumber(nearest[2]) - (tonumber(ARGV[2]) - interval);
    else
        
        redis.call('zadd', permitsName, ARGV[2], struct.pack('fI', ARGV[3], ARGV[1]));
        redis.call('decrby', valueName, ARGV[1]);
        return nil;
    end;
end;

參考:

https://github.com/oneone1995/blog/issues/13

https://www.infoq.cn/article/Qg2tX8fyw5Vt-f3HH673

到此這篇關(guān)于Redisson分布式限流器RRateLimiter的使用及原理小結(jié)的文章就介紹到這了,更多相關(guān)Redisson RRateLimiter內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Redis 高可用與集群原理深度解析

    Redis 高可用與集群原理深度解析

    Redis高可用機制涵蓋主從復制、哨兵自動故障轉(zhuǎn)移及Cluster集群分片與高可用,依賴Gossip協(xié)議實現(xiàn)節(jié)點通信與狀態(tài)同步,源碼解析了故障轉(zhuǎn)移流程,為后續(xù)持久化內(nèi)容奠定基礎(chǔ),本文給大家介紹Redis高可用與集群原理,感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • Redis妙用之存儲用戶token問題

    Redis妙用之存儲用戶token問題

    這篇文章主要介紹了Redis妙用之存儲用戶token問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Redis緩存的主要異常及解決方案實例

    Redis緩存的主要異常及解決方案實例

    這篇文章主要為大家介紹了Redis緩存的主要異常及解決方案實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01
  • Redis批量刪除Key的三種方式小結(jié)

    Redis批量刪除Key的三種方式小結(jié)

    本文主要介紹了Redis批量刪除Key的三種方式小結(jié),包括KEYS+DEL、SCAN+DEL、Lua腳本,需分批處理以減少風險,具有一定的參考價值,感興趣的可以了解一下
    2025-07-07
  • 深入理解Redis大key的危害及解決方案

    深入理解Redis大key的危害及解決方案

    本文主要介紹了深入理解Redis大key的危害及解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-01-01
  • redis中數(shù)據(jù)類型命令整理

    redis中數(shù)據(jù)類型命令整理

    在本篇文章里小編給大家整理的是關(guān)于redis中5種數(shù)據(jù)類型基本命令介紹,需要的朋友們可以學習下。
    2020-03-03
  • Redis中StringRedisTemplate中HashOperations的使用詳解

    Redis中StringRedisTemplate中HashOperations的使用詳解

    文章介紹了Spring Boot 2中使用Lettuce框架訪問Redis的基本步驟和常用操作,包括添加依賴、注入`StringRedisTemplate`實例以及進行字符串、哈希、集合、列表和有序集合的基本操作,文章還提供了一個登錄案例,并總結(jié)了個人經(jīng)驗,鼓勵讀者參考和支持
    2026-03-03
  • 關(guān)于Redis未授權(quán)訪問漏洞利用的介紹與修復建議

    關(guān)于Redis未授權(quán)訪問漏洞利用的介紹與修復建議

    Redis是一個開源的使用ANSI C語言編寫、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫,并提供多種語言的API,下面這篇文章主要給大家介紹了關(guān)于Redis未授權(quán)訪問漏洞利用的介紹和修復建議,文中介紹的非常詳細,需要的朋友可以參考下。
    2017-07-07
  • 監(jiān)聽Redis實時數(shù)據(jù)變化實現(xiàn)過程

    監(jiān)聽Redis實時數(shù)據(jù)變化實現(xiàn)過程

    本文介紹了通過定時遍歷Redis并對比緩存Map,實現(xiàn)監(jiān)聽指定前綴鍵的value變化的方法,并簡要提及了可用Keyspace通知等更高效的手段
    2025-10-10
  • 利用Supervisor管理Redis進程的方法教程

    利用Supervisor管理Redis進程的方法教程

    Supervisor 是可以在類 UNIX 系統(tǒng)中進行管理和監(jiān)控各種進程的小型系統(tǒng)。它自帶了客戶端和服務端工具,下面這篇文章主要給大家介紹了關(guān)于利用Supervisor管理Redis進程的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-08-08

最新評論

福建省| 镇雄县| 广昌县| 晋中市| 大冶市| 张家川| 潮安县| 根河市| 神池县| 沽源县| 霍林郭勒市| 衡阳市| 普兰店市| 清镇市| 杂多县| 苍南县| 芜湖县| 潜山县| 长阳| 泸水县| 邹平县| 新民市| 清新县| 广丰县| 柳林县| 焉耆| 洪雅县| 兰西县| 隆回县| 南和县| 和平区| 永嘉县| 桐乡市| 咸阳市| 吐鲁番市| 阆中市| 南阳市| 汨罗市| 怀宁县| 衡阳县| 库车县|