日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

redis实现轮询算法_【07期】Redis中是如何实现分布式锁的?

發布時間:2023/12/10 数据库 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 redis实现轮询算法_【07期】Redis中是如何实现分布式锁的? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

點擊上方“Java面試題精選”,關注公眾號

面試刷圖,查缺補漏

分布式鎖常見的三種實現方式:

  • 數據庫樂觀鎖;

  • 基于Redis的分布式鎖;

  • 基于ZooKeeper的分布式鎖。

  • 本地面試考點是,你對Redis使用熟悉嗎?Redis中是如何實現分布式鎖的。

    要點

    Redis要實現分布式鎖,以下條件應該得到滿足

    互斥性

    • 在任意時刻,只有一個客戶端能持有鎖。

    不能死鎖

    • 客戶端在持有鎖的期間崩潰而沒有主動解鎖,也能保證后續其他客戶端能加鎖。

    容錯性

    • 只要大部分的Redis節點正常運行,客戶端就可以加鎖和解鎖。

    實現

    可以直接通過?set key value px milliseconds nx?命令實現加鎖, 通過Lua腳本實現解鎖。

    //獲取鎖(unique_value可以是UUID等)
    SET?resource_name?unique_value?NX?PX??30000

    //釋放鎖(lua腳本中,一定要比較value,防止誤解鎖)
    if?redis.call("get",KEYS[1])?==?ARGV[1]?then
    ????return?redis.call("del",KEYS[1])
    else
    ????return?0
    end

    代碼解釋

    • set 命令要用?set key value px milliseconds nx,替代?setnx + expire?需要分兩次執行命令的方式,保證了原子性,

    • value 要具有唯一性,可以使用UUID.randomUUID().toString()方法生成,用來標識這把鎖是屬于哪個請求加的,在解鎖的時候就可以有依據;

    • 釋放鎖時要驗證 value 值,防止誤解鎖;

    • 通過 Lua 腳本來避免 Check And Set 模型的并發問題,因為在釋放鎖的時候因為涉及到多個Redis操作 (利用了eval命令執行Lua腳本的原子性);

    加鎖代碼分析

    首先,set()加入了NX參數,可以保證如果已有key存在,則函數不會調用成功,也就是只有一個客戶端能持有鎖,滿足互斥性。其次,由于我們對鎖設置了過期時間,即使鎖的持有者后續發生崩潰而沒有解鎖,鎖也會因為到了過期時間而自動解鎖(即key被刪除),不會發生死鎖。最后,因為我們將value賦值為requestId,用來標識這把鎖是屬于哪個請求加的,那么在客戶端在解鎖的時候就可以進行校驗是否是同一個客戶端。

    解鎖代碼分析

    將Lua代碼傳到jedis.eval()方法里,并使參數KEYS[1]賦值為lockKey,ARGV[1]賦值為requestId。在執行的時候,首先會獲取鎖對應的value值,檢查是否與requestId相等,如果相等則解鎖(刪除key)。

    存在的風險

    如果存儲鎖對應key的那個節點掛了的話,就可能存在丟失鎖的風險,導致出現多個客戶端持有鎖的情況,這樣就不能實現資源的獨享了。

  • 客戶端A從master獲取到鎖

  • 在master將鎖同步到slave之前,master宕掉了(Redis的主從同步通常是異步的)。主從切換,slave節點被晉級為master節點

  • 客戶端B取得了同一個資源被客戶端A已經獲取到的另外一個鎖。導致存在同一時刻存不止一個線程獲取到鎖的情況。

  • redlock算法出現

    這個場景是假設有一個 redis cluster,有 5 個 redis master 實例。然后執行如下步驟獲取一把鎖:

  • 獲取當前時間戳,單位是毫秒;

  • 跟上面類似,輪流嘗試在每個 master 節點上創建鎖,過期時間較短,一般就幾十毫秒;

  • 嘗試在大多數節點上建立一個鎖,比如 5 個節點就要求是 3 個節點 n / 2 + 1;

  • 客戶端計算建立好鎖的時間,如果建立鎖的時間小于超時時間,就算建立成功了;

  • 要是鎖建立失敗了,那么就依次之前建立過的鎖刪除;

  • 只要別人建立了一把分布式鎖,你就得不斷輪詢去嘗試獲取鎖。

  • Redis 官方給出了以上兩種基于 Redis 實現分布式鎖的方法,詳細說明可以查看:

    https://redis.io/topics/distlock 。

    Redisson實現

    Redisson是一個在Redis的基礎上實現的Java駐內存數據網格(In-Memory Data Grid)。它不僅提供了一系列的分布式的Java常用對象,還實現了可重入鎖(Reentrant Lock)、公平鎖(Fair Lock、聯鎖(MultiLock)、 紅鎖(RedLock)、 讀寫鎖(ReadWriteLock)等,還提供了許多分布式服務。

    Redisson提供了使用Redis的最簡單和最便捷的方法。Redisson的宗旨是促進使用者對Redis的關注分離(Separation of Concern),從而讓使用者能夠將精力更集中地放在處理業務邏輯上。

    Redisson 分布式重入鎖用法

    Redisson 支持單點模式、主從模式、哨兵模式、集群模式,這里以單點模式為例:

    //?1.構造redisson實現分布式鎖必要的Config
    Config?config?=?new?Config();
    config.useSingleServer().setAddress("redis://127.0.0.1:5379").setPassword("123456").setDatabase(0);
    //?2.構造RedissonClient
    RedissonClient?redissonClient?=?Redisson.create(config);
    //?3.獲取鎖對象實例(無法保證是按線程的順序獲取到)
    RLock?rLock?=?redissonClient.getLock(lockKey);
    try?{
    ????/**
    ?????*?4.嘗試獲取鎖
    ?????*?waitTimeout?嘗試獲取鎖的最大等待時間,超過這個值,則認為獲取鎖失敗
    ?????*?leaseTime???鎖的持有時間,超過這個時間鎖會自動失效(值應設置為大于業務處理的時間,確保在鎖有效期內業務能處理完)
    ?????*/
    ????boolean?res?=?rLock.tryLock((long)waitTimeout,?(long)leaseTime,?TimeUnit.SECONDS);
    ????if?(res)?{
    ????????//成功獲得鎖,在這里處理業務
    ????}
    }?catch?(Exception?e)?{
    ????throw?new?RuntimeException("aquire?lock?fail");
    }finally{
    ????//無論如何,?最后都要解鎖
    ????rLock.unlock();
    }

    加鎖流程圖

    解鎖流程圖

    我們可以看到,RedissonLock是可重入的,并且考慮了失敗重試,可以設置鎖的最大等待時間, 在實現上也做了一些優化,減少了無效的鎖申請,提升了資源的利用率。

    需要特別注意的是,RedissonLock 同樣沒有解決 節點掛掉的時候,存在丟失鎖的風險的問題。而現實情況是有一些場景無法容忍的,所以 Redisson 提供了實現了redlock算法的 RedissonRedLock,RedissonRedLock 真正解決了單點失敗的問題,代價是需要額外的為 RedissonRedLock 搭建Redis環境。

    所以,如果業務場景可以容忍這種小概率的錯誤,則推薦使用 RedissonLock, 如果無法容忍,則推薦使用 RedissonRedLock。

    參考

    https://github.com/javazhiyin/advanced-java/
    https://crazyfzw.github.io/2019/04/15/distributed-locks-with-redis/

    最近三期

    【04期】分庫分表之后,id 主鍵如何處理?

    【05期】消息隊列中,如何保證消息的順序性?

    【06期】單例模式有幾種寫法?

    精選常見面試題、技術知識點,幫助開發者查缺補漏。

    總結

    以上是生活随笔為你收集整理的redis实现轮询算法_【07期】Redis中是如何实现分布式锁的?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。