redis引入lua優勢

       Lua是一種功能強大,高效,輕量級,可嵌入的腳本語言。redis中Lua 腳本功能是 Reids 2.6 版本的最大亮點, 通過內嵌對 Lua 環境的支持, Redis 解決了長久以來不能高效地處理 CAS (check-and-set)命令的缺點, 並且可以通過組合使用多個命令, 輕鬆實現以前很難實現或者不能高效實現的模式。  

      redis中引入lua的優勢:

  • 減少網絡開銷:多個請求通過腳本一次發送,減少網絡延遲
  • 原子操作:將腳本作爲一個整體執行,中間不會插入其他命令,無需使用事務
  • 複用:客戶端發送的腳本永久存在redis中,其他客戶端可以複用腳本
  • 可嵌入性:可嵌入JAVA,C#等多種編程語言,支持不同操作系統跨平臺交互

 

     redis中lua腳本應用:使用lua腳本實現分佈式鎖的釋放。

     詳細介紹參考:https://www.cnblogs.com/demingblog/p/9542124.html

     具體代碼實現如下:   

public static final String UNLOCK_LUA;
static {
    StringBuilder sb = new StringBuilder();
    sb.append("if redis.call(\"get\",KEYS[1]) == ARGV[1] ");
    sb.append("then ");
    sb.append("    return redis.call(\"del\",KEYS[1]) ");
    sb.append("else ");
    sb.append("    return 0 ");
    sb.append("end ");
    UNLOCK_LUA = sb.toString();
}

public boolean releaseLock(String key, String requestId) {
        // 釋放鎖的時候,有可能因爲持鎖之後方法執行時間大於鎖的有效期,此時有可能已經被另外一個線程持有鎖,所以不能直接刪除
        try {
            List<String> keys = new ArrayList<>();
            keys.add(key);
            List<String> args = new ArrayList<>();
            args.add(requestId);

            // 使用lua腳本刪除redis中匹配value的key,可以避免由於方法執行時間過長而redis鎖自動過期失效的時候誤刪其他線程的鎖
            // spring自帶的執行腳本方法中,集羣模式直接拋出不支持執行腳本的異常,所以只能拿到原redis的connection來執行腳本
            RedisCallback<Long> callback = (connection) -> {
                Object nativeConnection = connection.getNativeConnection();
                // 集羣模式和單機模式雖然執行腳本的方法一樣,但是沒有共同的接口,所以只能分開執行
                // 集羣模式
                if (nativeConnection instanceof JedisCluster) {
                    return (Long) ((JedisCluster) nativeConnection).eval(UNLOCK_LUA, keys, args);
                }

                // 單機模式
                else if (nativeConnection instanceof Jedis) {
                    return (Long) ((Jedis) nativeConnection).eval(UNLOCK_LUA, keys, args);
                }
                return 0L;
            };
            Long result = redisTemplate.execute(callback);

            return result != null && result > 0;
        } catch (Exception e) {
            logger.error("release lock occured an exception", e);
        } finally {
            // 清除掉ThreadLocal中的數據,避免內存溢出
            // lockFlag.remove();
        }
        return false;
    }


 

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