成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一個Redis分布式鎖的實現引發的思考

數據庫 Redis
釋放鎖時,會通過 UUID 去判斷這個鎖的值,避免釋放其他線程加的鎖,但是沒有考慮到這個 get 和 del 是兩個操作,還是會有意外,比如 releaseLock 時,執行完 get ,判斷這個 uuid 是自己的,準備刪除,但此時 鎖過期 了,其他線程剛好加鎖成功,結果又被你刪除了。

最近看了一個老項目(2018年的),發現其中用 Redis 來實現分布式鎖??。

代碼如下 ??

// jedis 

public String lock(String lockName, long acquireTimeout) {
    return lockWithTimeout(lockName, acquireTimeout, DEFAULT_EXPIRE);
}

public String lockWithTimeout(String lockName, long acquireTimeout, long timeout) {

        RedisConnectionFactory connectionFactory = redisTemplate.getConnectionFactory();
        RedisConnection redisConnection = connectionFactory.getConnection();
        /** 隨機生成一個value */
        String identifier = UUID.randomUUID().toString();
        String lockKey = LOCK_PREFIX + lockName;
        int lockExpire = (int) (timeout / 1000);

        long end = System.currentTimeMillis() + acquireTimeout;    /** 獲取鎖的超時時間,超過這個時間則放棄獲取鎖 */
        while (System.currentTimeMillis() < end) {
            if (redisConnection.setNX(lockKey.getBytes(), identifier.getBytes())) {
                redisConnection.expire(lockKey.getBytes(), lockExpire);
                /** 獲取鎖成功,返回標識鎖的value值,用于釋放鎖確認 */
                RedisConnectionUtils.releaseConnection(redisConnection, connectionFactory);
                return identifier;
            }
            /** 返回-1代表key沒有設置超時時間,為key設置一個超時時間 */
            if (redisConnection.ttl(lockKey.getBytes()) == -1) {
                redisConnection.expire(lockKey.getBytes(), lockExpire);
            }
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                log.warn("獲取分布式鎖:線程中斷!");
                Thread.currentThread().interrupt();
            }
        }
        RedisConnectionUtils.releaseConnection(redisConnection, connectionFactory);
        return null;
    }

public boolean releaseLock(String lockName, String identifier) {

    if (StringUtils.isEmpty(identifier)) return false;

    RedisConnectionFactory connectionFactory = redisTemplate.getConnectionFactory();
    RedisConnection redisConnection = connectionFactory.getConnection();
    String lockKey = LOCK_PREFIX + lockName;
    boolean releaseFlag = false;
    while (true) {
        try {
            byte[] valueBytes = redisConnection.get(lockKey.getBytes());

            /**  value為空表示鎖不存在或已經被釋放*/
            if (valueBytes == null) {
                releaseFlag = false;
                break;
            }

            /** 通過前面返回的value值判斷是不是該鎖,若是該鎖,則刪除,釋放鎖 */
            String identifierValue = new String(valueBytes);
            if (identifier.equals(identifierValue)) {
                redisConnection.del(lockKey.getBytes());
                releaseFlag = true;
            }
            break;
        } catch (Exception e) {
            log.warn("釋放鎖異常", e);
        }
    }
    RedisConnectionUtils.releaseConnection(redisConnection, connectionFactory);
    return releaseFlag;
}


public void lockTest(String lockName, Long acquireTimeout, CouponSummary couponSummary)  {

    String lockIdentify = redisLock.lock(lockName,acquireTimeout);
    if (StringUtils.isNotEmpty(lockIdentify)){
        // 業務代碼
        redisLock.releaseLock(lockName, lockIdentify);
    }
    else{
        System.out.println("get lock failed.");
    }

}

分析

看完之后,有這幾點感悟

  1. setNX 和 expire 兩個操作是分開的,有一定的風險(忘了釋放鎖,expire 失敗)
  2. 加鎖時,除了 setNX ,還會去 ttl ,防止死鎖的發生。
  3. 釋放鎖時,會通過 UUID 去判斷這個鎖的值,避免釋放其他線程加的鎖,但是沒有考慮到這個 get 和 del 是兩個操作,還是會有意外,比如 releaseLock 時,執行完 get ,判斷這個 uuid 是自己的,準備刪除,但此時 鎖過期 了,其他線程剛好加鎖成功,結果又被你刪除了。
  4. 釋放鎖時沒有在 finally 塊中執行
  5. 獲取不到鎖時,嘗試自旋等待鎖

再結合 redisson 框架來看的話,就會發現

  1. 少了 自動續期 的功能,如果業務執行時間較長,鎖過期釋放掉了,就可能出現并發問題。
  2. 少了 可重入鎖 的功能,可以預見獲取鎖的線程,再次去加鎖也會失敗。
  3. 少了 lua腳本 ,lua 腳本能保證原子性操作,減少這個網絡開銷。

再把視角移到 Redis 服務器來,就會發現 單點問題 的存在,此時分布式鎖就無法使用了。

這個問題可以通過 主從,哨兵,集群 模式解決,但是又有了一個 故障轉移問題 。

先簡要介紹下這幾個模式

  1. Redis 主從復制模式:

一主多從,主節點負責寫,并同步到從節點。

從節點負責備份數據,處理讀操作,提供讀負載均衡和故障切換。

  1. Redis 哨兵模式:
  • 主從基礎上增加了哨兵節點(Sentinel),一個獨立進程,去監控所有節點,當主節點宕機時,會從 slave 中選舉出新的主節點,并通知其他從節點更新配置
  • 哨兵節點負責執行故障轉移、選舉新的主節點等操作
  1. Redis 集群模式:
  • 多個主從組成,由 master 去瓜分 16384 個 slot, 將數據分片存儲在多個節點上。
  • 節點間通過 Gossip 協議進行廣播通信,比如 新節點的加入,主從變更等

回到 分布式鎖 這個話題,通過主從切換,可以實現故障轉移。但是當加鎖成功時,master 掛了,此時還沒同步鎖信息到這個 slave 上,那這個分布式鎖也是失效了。

網上的方案是通過  Redlock(紅鎖) 來解決。

Redlock 的大致意思就是給多個節點加鎖,超過半數成功的話,就認為加鎖成功。

redisson 的紅鎖用法??

RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");

RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
// 同時加鎖:lock1 lock2 lock3
// 紅鎖在大部分節點上加鎖成功就算成功。
lock.lock();
...
lock.unlock();

我更偏向于解決這個 主從復制延遲 的問題,比如

  • 升級硬件,更好的 CPU,帶寬
  • 避免從節點阻塞,比如操作一些 大Key
  • 調大 repl_backlog_size 參數,避免全量同步

當然,具體問題具體分析,可以根據業務準備補償措施,但也要避免這個過度設計。

紅鎖爭論

在查閱資料時,看到了這么一個事情 ??

《數據密集型應用系統設計》的作者 Martin 去反駁這個 Redlock ,并用一個進程暫停(GC)的例子,指出了 Redlock 安全性問題:

  1. 客戶端 1 請求鎖定節點 A、B、C、D、E
  2. 客戶端 1 的拿到鎖后,進入 GC(時間比較久)
  3. 所有 Redis 節點上的鎖都過期了
  4. 客戶端 2 獲取到了 A、B、C、D、E 上的鎖
  5. 客戶端 1 GC 結束,認為成功獲取鎖
  6. 客戶端 2 也認為獲取到了鎖,發生「沖突」

圖片圖片

還有 時鐘 漂移的問題

這里我就不過多 CV 了,可以看看原文??

相關文章

《一文講透Redis分布式鎖安全問題》:https://cloud.tencent.com/developer/article/2332108

《How to do distributed locking》https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html

NPC 異常場景

  • N:Network Delay,網絡延遲
  • P:Process Pause,進程暫停(GC)
  • C:Clock Drift,時鐘漂移
責任編輯:武曉燕 來源: Java4ye
相關推薦

2020-07-30 09:35:09

Redis分布式鎖數據庫

2021-11-01 12:25:56

Redis分布式

2022-04-14 07:56:30

公平鎖Java線程

2024-02-19 00:00:00

Redis分布式

2019-06-19 15:40:06

分布式鎖RedisJava

2024-07-15 08:25:07

2023-03-01 08:07:51

2022-09-22 13:28:34

Redis分布式鎖

2022-09-29 08:28:57

SpringRedis分布式

2022-01-06 10:58:07

Redis數據分布式鎖

2023-08-21 19:10:34

Redis分布式

2020-05-12 14:03:51

RedisZooKeeper分布式鎖

2024-11-28 15:11:28

2019-02-26 09:51:52

分布式鎖RedisZookeeper

2022-12-18 20:07:55

Redis分布式

2023-09-21 22:22:51

開發分布式鎖

2023-10-11 09:37:54

Redis分布式系統

2024-10-07 10:07:31

2019-12-25 14:35:33

分布式架構系統

2024-04-01 05:10:00

Redis數據庫分布式鎖
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品免费一区二区三区四区 | 亚洲精品第一国产综合野 | 97视频在线观看免费 | 午夜精品久久久久久久99黑人 | caoporn地址 | 久久99国产精品 | 国产一级一级毛片 | 国产精品高潮呻吟久久 | 午夜小电影 | av资源中文在线 | 久久久国产一区 | 精品在线播放 | 天天舔天天 | 美女视频黄色片 | 中文一区 | 成人在线免费网站 | 羞羞视频网站免费观看 | 丁香色婷婷 | 国产一区二区三区免费 | 91视频在线 | 日韩毛片 | 亚洲一区二区视频 | 久久青草av | 一区二区国产在线观看 | 91精品一区二区三区久久久久久 | 国产亚洲人成a在线v网站 | 日韩 欧美 综合 | av无遮挡 | 日日夜夜精品 | 久久高清免费视频 | 天堂资源最新在线 | 日韩免费福利视频 | 99精品视频在线观看免费播放 | 亚洲国产成人av好男人在线观看 | 中文字幕一区二区三区在线乱码 | 久久99精品久久久水蜜桃 | 国产成人亚洲精品 | 国产大学生情侣呻吟视频 | 国产精品呻吟久久av凹凸 | 欧美激情99| 免费观看色 |