RPermitExpirableSemaphore使用筆記

2020-10-28 18:06:02

RPermitExpirableSemaphore是什麼

首先,RPermitExpirableSemaphore 是出自於Redisson,Redisson是一個在Redis的基礎上實現的Java駐記憶體資料網格(In-Memory Data Grid),Redisson也是redis官方推薦的,比較常用的是它的分散式鎖。
Redisson中文檔案:
https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95
RPermitExpirableSemaphore ,可過期性號誌
介面檔案:
https://www.javadoc.io/doc/org.redisson/redisson/latest/index.html

用法

舉個栗子
建立RedissonClient 單機版

 @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        // 單機模式
        config.useSingleServer()
                .setAddress("redis://127.0.0.1:6379")
        ;
                return Redisson.create(config);
    }

一次完整的獲得許可,釋放許可

  public void test() throws Exception {
        //通過redissonClient創造一個key為xxx的號誌
        RPermitExpirableSemaphore semaphore = redissonClient.getPermitExpirableSemaphore("xxx");
        //給號誌設定數量為5,用在限流中就是隻允許5次請求
        while (!semaphore.trySetPermits(5)) ;

        //tryAcquire 的第一個引數是waittime,嘗試獲得許可證的最大等待時間,超過這個時間則返回null
        //第二個引數是許可證的過期時間,也是精華所在,即使發生宕機,jvm崩潰等情況,也不用擔心,號誌過期會自動釋放
        //成功之後會獲得一個許可證ID,是在獲取期間每次生成的128位元唯一隨機識別符號
        String permitId = semaphore.tryAcquire(1, 5, TimeUnit.SECONDS);
        System.out.println(permitId);
        //釋放許可證還需要之前獲得permitId
        semaphore.release(permitId);
    }

semaphore.trySetPermits() 中 lua指令碼分析

@Override
    public RFuture<Boolean> trySetPermitsAsync(int permits) {
        return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
                "local value = redis.call('get', KEYS[1]); " +
                //value==0或者false,都是代表沒有這個號誌,進入建立號誌的邏輯
                "if (value == false or value == 0) then "
                //所謂建立,其實就是redis的set操作, ARGV[1]即為要設定的許可數
                    + "redis.call('set', KEYS[1], ARGV[1]); "
                    + "redis.call('publish', KEYS[2], ARGV[1]); "
                    + "return 1;"
                + "end;"
                + "return 0;",
                Arrays.<Object>asList(getName(), getChannelName()), permits);
    }

異常記錄

1.Caused by: org.redisson.client.RedisException: ERR This instance has cluster support disabled. channel: [id: 0x0fd46049, L:/127.0.0.1:62555 - R:/127.0.0.1:6379] command: CommandData [promise=org.redisson.misc.RedissonPromise@74bd3426[Not completed], command=(CLUSTER NODES), params=[], codec=null]
是由於設定了叢集

 Config config = new Config();
        // set叢集版報錯
        config.useClusterServers()
                .addNodeAddress("redis://127.0.0.1:6379")

應該為

 config.useSingleServer()
                .setAddress("redis://127.0.0.1:6379")

2.trySetPermits 一直返回的false,可以檢視下是否redis中有了相同的key,trySetPermits 其實就是往redis中塞值。