<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 22, comments - 32, trackbacks - 0, articles - 73
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    分布式鎖實現-redis,zk

    Posted on 2021-03-24 20:11 為自己代言 閱讀(206) 評論(0)  編輯  收藏 所屬分類: java/J2EE
    1:分布鎖有好多實現方式
    •  基于數據庫實現
          這個實現方式比較復雜,考慮因素比較多,比如:超時,非公平鎖,非重入等會有各種各樣的問題,在解決問題的過程中會使整個方案變得越來越復雜。操作數據庫需要一定的開銷,性能問題需要考慮      
    • 基于redis實現(這個對于不太敏感的場景可以使用,由于redis集群和單機,還有客戶端,版本等多方面因素考慮情況比較多)
           性能好。使用緩存實現分布式鎖的缺點 其數據庫一樣
    • 基于zookeeper實現(這個是最終也是最好最可靠的)
           創建臨時節點,可以解決單機,鎖無法釋放,非阻塞,不可沖入,非公平的問題
     
        總結
    從理解的難易程度角度(從低到高)

    數據庫 > 緩存 > Zookeeper

    從實現的復雜性角度(從低到高)

    Zookeeper > 緩存 > 數據庫

    從性能角度(從高到低)

    緩存 > Zookeeper >= 數據庫

    從可靠性角度(從高到低)

    Zookeeper > 緩存 > 數據庫
    下面講基于redis實現分布鎖代碼:RedisTemplate 客戶端 lettuce


    @Service
    public class RedisDistributedLockUtils {

        @Autowired
        
    private RedisTemplate redisTemplate;

        
    private static final Long RELEASE_SUCCESS = 1L;

        
    private static final long DEFAULT_TIMEOUT = 1000 * 10;
        
    //因為要使用lua 腳本是因為 redis 執行lua腳本是原子操作
        private static final String UNLOCK_LUA= "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

        
    /**
         * 實時獲取鎖
         *
         * 嘗試獲取分布式鎖 將redis版本升級到2.1以上(spring-boot-starter-data-redis 版本 2.X以上),然后使用setIfAbsent 不存在
         * 當setIfAbsent成功之后斷開連接,下面設置過期時間的代碼 stringRedisTemplate.expire(key,timeout);是無法執行的,這時候就會有大量沒有過期時間的數據存在數據庫
         * 
    @param lockKey    鎖
         * 
    @param requestId  請求標識
         * 
    @param expireTime 超期時間
         * 
    @return 是否獲取成功
         
    */
        
    public boolean trySetDistributedLock(String lockKey, String requestId, long expireTime) {
            
    return redisTemplate.opsForValue().setIfAbsent(lockKey, requestId,0 == expireTime ? DEFAULT_TIMEOUT : expireTime, TimeUnit.MILLISECONDS);
        }

        
    /**
         * 以阻塞方式的獲取鎖
         * 
    @param key
         * 
    @param value
         * 
    @param timeout
         * 
    @return
         
    */
        
    public boolean setDistributedLock(String key, String value, long timeout) {
            Boolean lock 
    = false;
            
    long start = System.currentTimeMillis();
            
    while (!lock && (System.currentTimeMillis() - start < timeout)) {
                
    //執行set命令
                lock = redisTemplate.opsForValue().setIfAbsent(key, value, timeout, TimeUnit.MILLISECONDS);
                
    //不頻繁去獲取鎖
                try {
                    
    if (!lock) {
                        Thread.sleep(
    60);
                    }
                } 
    catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
    return lock;
        }

        
    public boolean releaseLock(String key, String value) {
            
    // 使用Lua腳本:先判斷是否是自己設置的鎖,再執行刪除
            
    // 使用lua腳本刪除redis中匹配value的key,可以避免由于方法執行時間過長而redis鎖自動過期失效的時候誤刪其他線程的鎖
            
    // spring自帶的執行腳本方法中,集群模式直接拋出不支持執行腳本的異常EvalSha is not supported in cluster environment
            
    // 所以只能拿到原redis的connection來執行腳本

            List
    <String> keys = new ArrayList<>();
            keys.add(key);
            List
    <String> args = new ArrayList<>();
            args.add(value);
            Long result 
    = (Long)redisTemplate.execute(new RedisCallback<Long>() {
                @Override
                
    public Long doInRedis(RedisConnection connection) throws DataAccessException {
                    Object nativeConnection 
    = connection.getNativeConnection();
                    
    // 集群模式和單機模式雖然執行腳本的方法一樣,但是沒有共同的接口,所以只能分開執行
                    
    // 集群模式
                    if (nativeConnection instanceof JedisCluster) {
                        
    return (Long)((JedisCluster)nativeConnection).eval(UNLOCK_LUA, keys, args);
                    }
                    
    //客戶端是Jedis時候(單機模式)
                    else if (nativeConnection instanceof Jedis) {
                        
    return (Long)((Jedis)nativeConnection).eval(UNLOCK_LUA, keys, args);
                    }
                    
    //這里使用 redisTemplate 中lettuce 客戶端
                    else{
                        DefaultRedisScript
    <Long> redisScript = new DefaultRedisScript<>();
                        redisScript.setScriptText(UNLOCK_LUA);
                        redisScript.setResultType(Long.
    class);
                        
    return (Long)redisTemplate.execute(redisScript, keys, value);
                    }
                }
            });
            
    //返回最終結果
            return RELEASE_SUCCESS.equals(result);
        }
    }
    基于zookeeper實現下期補上:


    介紹分布式鎖文章寫的比較詳細:
    https://blog.csdn.net/u010963948/article/details/79006572
    主站蜘蛛池模板: 最近中文字幕免费大全| 国产无遮挡又黄又爽免费视频| 亚洲美女视频网址| 大地资源在线观看免费高清| 日韩亚洲人成在线综合| 亚洲欧洲无码AV电影在线观看 | 国产无限免费观看黄网站| 久久青青草原亚洲AV无码麻豆 | 亚洲AV无码之日韩精品| 国产精品视频白浆免费视频| 亚洲七久久之综合七久久| 亚洲精品无码Av人在线观看国产| 在线视频观看免费视频18| xxxxx做受大片在线观看免费| 久久精品国产亚洲av麻豆色欲| 四虎在线播放免费永久视频| 亚欧日韩毛片在线看免费网站| 国产精品亚洲综合天堂夜夜| 久久精品亚洲中文字幕无码麻豆| 免费国产在线观看不卡| 亚欧色视频在线观看免费| 一级黄色免费大片| 最新亚洲卡一卡二卡三新区| 亚洲AV日韩精品久久久久久| 免费在线视频一区| 午夜神器成在线人成在线人免费| 久久久久久免费一区二区三区 | 精品亚洲AV无码一区二区三区| 亚洲综合国产精品第一页| 成人五级毛片免费播放| 99精品视频在线免费观看 | 色影音免费色资源| 两性色午夜视频免费网| 日本系列1页亚洲系列| 亚洲av无码电影网| 麻豆亚洲AV永久无码精品久久| 国产亚洲午夜高清国产拍精品 | 亚洲欧洲日产国产综合网| 亚洲精品成a人在线观看| 好爽…又高潮了免费毛片| 曰批全过程免费视频播放网站 |