成人免费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技術棧公眾號

主站蜘蛛池模板: 激情影院久久 | 天天操 天天操 | 午夜丁香视频在线观看 | 久一久 | 精品欧美一区二区在线观看欧美熟 | 色婷婷精品国产一区二区三区 | 国产精品自产av一区二区三区 | 国产精品久久久久永久免费观看 | 欧美一区二区三区国产精品 | 一本久久a久久精品亚洲 | 国产成人精品免费视频大全最热 | 一级黄色毛片a | 麻豆一区 | 国产欧美日韩精品一区 | 久久尤物免费一区二区三区 | 视频一区中文字幕 | 一区二区在线不卡 | 国产成人精品一区二区三区网站观看 | 鲁一鲁资源影视 | 久久久网| 中国大陆高清aⅴ毛片 | 亚洲国产成人久久综合一区,久久久国产99 | 欧美一区二区免费视频 | 国产精品一区二区在线免费观看 | 精品av | 在线欧美小视频 | 超级黄色一级片 | 国产美女自拍视频 | 久久激情视频 | 日韩中文字幕网 | 激情国产 | 成人在线视频网站 | 欧美国产亚洲一区二区 | 免费高潮视频95在线观看网站 | 国产在线视频在线观看 | 乳色吐息在线观看 | 精品一二区 | 99这里只有精品 | 亚洲一区 中文字幕 | 福利片在线观看 | 中文字幕一区二区三区不卡 |