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

歡迎訪問 生活随笔!

生活随笔

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

数据库

redis 分布式锁 看门狗_漫谈分布式锁之Redis实现

發布時間:2024/10/14 数据库 88 豆豆
生活随笔 收集整理的這篇文章主要介紹了 redis 分布式锁 看门狗_漫谈分布式锁之Redis实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

筆耕墨耘,深研術道。

01寫在前面Redis是一個高性能的內存數據庫,常用于數據庫、緩存和消息中間件。它提供了豐富的數據結構,更適合各種業務場景;基于AP模型,Redis保證了其高可用和高性能。

本文主要內容:

  • Redis實現分布式鎖的依據
  • 基于setnx +?expire的不斷探索

  • 分布式利器—Redisson

  • Redlock算法及其爭議
02Redis實現分布式鎖的依據

Redis分布式鎖的實現的核心依據:redis的單線程模型,保證最終只有一個setnx命令可以執行成功;

如何理解Redis的單線程模型(選讀)?

Redis基于Reactor模式開發了自己網絡事件處理器:這個處理器被稱為文件事件處理器(file event handler):
  • 文件事件處理器使用I/O多路復用(multiplexing)程序來同時監聽多個套接字,并根據套接字目前執行的任務來為套接字關聯不同的事件處理器;

  • 當被監聽的套接字準備好執行連接應答(accept)、讀取(read)、寫入(write)、關閉(close)等操作時,與操作相對應的文件事件就會產生,這時文件事件處理器就會調用套接字之前關聯好的事件處理器來處理這些事件。

注:文件事件處理器是統稱,是網絡事件處理的模塊(或者說方案),其包括四個組成部分:套接字、I/O多路復用程序、文件事件分派器(dispatcher),以及事件處理器。

文件事件處理器四個組成部分如下:

文件事件處理器的四個組成部分

  • I/O多路復用程序負責監聽多個套接字,對于產生了事件的套接字,將它們放入一個隊列里面,然后通過這個隊列,以有序、同步、每次一個套接字的方式向文件事件分派器傳送套接字(單線程模型);

  • 當上一個套接字產生的事件被處理完畢之后,I/O多路復用程序才會繼續向文件事件分派器傳送下一個套接字;

  • 文件事件分派器接受I/O多路復用程序傳來的套接字,并根據套接字產生的事件類型,調用相應的事件處理器;

  • 這些事件處理器是一個個函數,它們會執行相應的操作。

總結:雖然文件事件處理器以單線程方式運行,但通過使用I/O多路復用程序來監聽多個套接字,文件事件處理器既實現了高性能的網絡通信模型,又可以很好地與Redis服務器中其他同樣以單線程方式運行的模塊進行對接,這保持了Redis內部單線程設計的簡單性。03基于setnx +?expire的不斷探索為了代碼的復用和可維護性,這里提供一個分布式鎖的接口,各個版本的方案均實現了此接口。

基本實現代碼:這里給出了阻塞和非阻塞兩種方式。

public interface DistributedLock { ? ?/** ? ? * 阻塞 ? ? * ? ? * @param lockKey ? ? * @param timeout ? ? */????void?lock(String?lockKey,?long?timeout); ? ?/** ? ? * 非阻塞 ? ? * ? ? * @param lockKey ? ? * @param timeout ? ? * @return ? ? */????boolean?tryLock(String?lockKey,?long?timeout); ? ?/** ? ? * 釋放鎖 ? ? * ? ? * @param lockKey ? ? */????void?unlock(String?lockKey);}

利用stringRedisTemplate實現,以下代碼并不嚴謹,僅僅是演示某些問題。

@Override public void lock(String lockKey, long timeout) { BoundValueOperations<String, String> boundValueOps = stringRedisTemplate.boundValueOps(lockKey); while (true) { Boolean b = boundValueOps.setIfAbsent("1"); if (b) { Boolean expire = boundValueOps.expire(timeout, TimeUnit.SECONDS); if (expire) { return; } } // 休眠1s后再重試 LockSupport.parkNanos(1*1000*1000); } } @Override public boolean tryLock(String lockKey, long timeout) { BoundValueOperations<String, String> boundValueOps = stringRedisTemplate.boundValueOps(lockKey); Boolean b = boundValueOps.setIfAbsent("1"); if (b) { Boolean expire = boundValueOps.expire(timeout, TimeUnit.SECONDS); if (expire) { return true; } } return false; } @Override public void unlock(String lockKey) { stringRedisTemplate.delete(lockKey); }

上述代碼,是一種簡單的分布式鎖的實現,但是問題也較明顯:

  • 非原子性:setnx + expire兩條命令非原子操作,有可能導致死鎖;

  • 鎖誤解除:B線程加的鎖,可能被A線程釋放掉,導致鎖失效;

  • 超時并發:業務執行時間超過鎖超時時間,導致鎖失效,產生并發安全問題;

  • 不可重入:不支持可重入;

  • 集群問題:Redis哨兵模式和集群模式帶來的問題,主從發生failover時候帶來的鎖失效。

針對以上問題,提供以下解決方案:

Q1非原子性
  • 方案一:在高版本redis中(Redis 2.6.12以后),官方完善了setnx:SET key value [EX seconds] [PX milliseconds] [NX|XX];

  • 方案二:使用LUA腳本,如下:

if (redis.call('setnx', KEYS[1], ARGV[1]) < 1)then return 0;end;redis.call('expire', KEYS[1], tonumber(ARGV[2]));return 1;Q2 & Q3鎖誤解除和鎖超時并發

如下圖:

當鎖超時釋放后,會有其他線程爭搶鎖。此時,會發生線程A釋放了線程B占用鎖的情況,并且會導致鎖失效產生并發問題(圖中棕色所示)。針對鎖誤解除的問題,可以:
  • 加鎖時候,設置value值,這個value值來標記當前線程,嚴格來說,該值在所有客戶端和所有鎖定請求中必須唯一。

This?value?must?be?unique?across?all?clients?and?all?lock?requests.

  • 在解鎖的時候判斷解鎖線程是否是占有鎖的線程,出于安全性(原子性)考慮,這段解鎖邏輯使用LUA腳本編寫。如下:

Basically?the?random?value?is?used?in?order?to?release?the?lock?in?a?safe?way,?with?a?script?that?tells?Redis:?remove?the?key?only?if?it?exists?and?the?value?stored?at?the?key?is?exactly?the?one?I?expect?to?be.

if redis.call("get",KEYS[1]) == ARGV[1] then ? ?return redis.call("del",KEYS[1])else ? ?return 0end

針對鎖超時帶來的并發問題,可以:

為獲取鎖的線程(圖中線程A)設置一個守護線程,守護線程周期性地給當前鎖續期,當線程A執行完成任務,會顯示關閉守護線程;即使線程A掛掉,由于線程A和守護線程在同一個進程,守護線程也會停下。這把鎖到了超時的時候,沒人給它續命,也就自動釋放了。如下圖:

補充:Redisson的鎖續期實現,基于netty的時間輪算法。

Q4不可重入

參考Redisson利用hash數據結構實現對線程的重入計數。這個問題將在Redisson分布式鎖源碼分析里面講述。

Q5集群問題

我們知道Redis的主從復制是異步的,主從發生failover時將帶來鎖失效問題。

What?happens?if?the?Redis?master?goes?down??Well,?let’s?add?a?slave!?And?use?it?if?the?master?is?unavailable.?This?is?unfortunately?not?viable.?By?doing?so?we?can’t?implement?our?safety?property?of?mutual?exclusion,?because?Redis?replication?is?asynchronous.

如上圖所示:

  • 左邊client在Master獲取到鎖;

  • 在將鎖信息同步到slave之前,master掛掉,此時發生failover;

  • slave節點升級為新的master(New Master),此時,其他線程來獲取鎖,發現并沒有其他線程占用,也加鎖成功。這導致了鎖失效。
解決方案:

可以使用Redlock算法。

We?propose?an?algorithm,?called?Redlock,?which?implements?a?DLM?which?we?believe?to?be?safer?than?the?vanilla?single?instance?approach.

04分布式利器—Redisson

Redisson是一個在Redis的基礎上實現的Java駐內存數據網格(In-Memory Data Grid)。它不僅提供了一系列的分布式的Java常用對象,還提供了許多分布式服務。這里我們關注其對分布式鎖的支持,它解決了我們上面論述的幾種問題。

概覽Redisson鎖的實現

如上圖Redisson的類圖,總結常用對象:

  • 可重入鎖(Reentrant Lock)

  • 公平鎖(Fair Lock)

  • 聯鎖(MultiLock)

  • 紅鎖(RedLock)

  • 讀寫鎖(ReadWriteLock)

  • 信號量(Semaphore)

這里我們以RedissonLock(最常用的)為例,了解下其常用的一些api:

public void lock();//?不建議使用,鎖續期僅僅在leaseTime = -1時生效public void lock(long leaseTime, TimeUnit unit);public boolean tryLock();// 不建議使用,鎖續期僅僅在leaseTime = -1時生效public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit);public boolean tryLock(long waitTime, TimeUnit unit);

上述api的實際使用,這里不再演示,相對比較簡單,可以通過其官網學習:

https://github.com/redisson/redisson/wiki

注意事項

  • 鎖續期生效的場景:鎖續期僅僅在leaseTime = -1時生效;

  • 鎖【lock.lock()】的使用必須緊跟try代碼塊,且unlock要放到finally塊第一行。這點是阿里規范,說明如下:

05Redlock算法及其爭議為了解決集群環境下,分布式鎖的缺陷,Antirez發明了Redlock算法,它的實現流程比較復雜,不過業界已經有很多開源的類庫封裝實現了。比如Redisson提供的RedissonRedLock對象,其實現了Redlock描述的加鎖算法。
Redlock算法

為了使用Redlock算法,需要提供多個Redis實例,并且這些實例之間相互獨立,沒有主從關系(不會有數據的同步等)。同很多分布式算法一樣,Redlock也使用大多數機制。加鎖時候,它會向過半節點發送set(key,value,nx=True,ex=xxx)指令,只要過半節點set成功,就認為加鎖成功。釋放鎖時候,需要向所有節點發送del指令。不過Redlock算法還需要考慮超時問題、出錯重試、時鐘漂移等很多細節問題,同時因為Redlock需要向多個節點進行讀寫,意味著其相比單實例的Redis的性能會下降一些。

Redlock算法的爭議
可以參閱:

[1] https://redis.io/topics/distlock

[2] http://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html

[3] http://antirez.com/news/101

06總結至此,簡單介紹了分布式鎖基于Redis的實現。實際項目中建議使用Redisson提供的鎖來保證臨界資源的安全性。對于追求業務強一致的業務場景,可以利用分布式協調器來實現,如基于zookeeper的實現,這將在后面提到。07引用[1] https://redis.io/topics/distlock

[2] https://github.com/redisson/redisson/wiki

[3] https://mp.weixin.qq.com/s/8fdBKAyHZrfHmSajXT_dnA

[4] https://learnku.com/articles/47769

[5] 黃健宏,《Redis設計與實現》,機械工業出版社

[6] Josiah?L. Carlson,黃健宏,《Redis實戰》,中國工信出版社

[7] 錢文品,《Redis深度歷險》,中國工信出版社

發現“在看”和“贊”了嗎,戳我試試吧

總結

以上是生活随笔為你收集整理的redis 分布式锁 看门狗_漫谈分布式锁之Redis实现的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 成人午夜网站 | 毛片大全免费看 | 西欧free性满足hd老熟妇 | 国产91清纯白嫩初高中在线观看 | 一级黄色片一级黄色片 | 伊人网在线免费观看 | 欧美一级三级 | 国产精品卡一 | 中文字幕h | 欧美黄色一级网站 | 99久久婷婷国产综合精品草原 | 成人理论片 | 亚洲成熟丰满熟妇高潮xxxxx | 男人的天堂在线播放 | 国产福利视频 | 国产精品二区在线观看 | 日本一区中文字幕 | 国产suv精品一区二区三区 | 中文字幕在线观看二区 | 国产精品少妇 | 性欧美视频 | 国产精品视频福利 | 中文字幕导航 | 第色| 无码熟妇αⅴ人妻又粗又大 | 免费高清欧美大片在线观看 | 夫妻性生活黄色大片 | 在线无遮挡 | 夜夜操夜夜爽 | 日韩欧美一区二区三区久久婷婷 | 波多野吉衣一二三区乱码 | 在线一区二区视频 | 色射网 | xxxxx在线观看 | 男生c女生 | 鸭子av | 久久久久久久久久影视 | 成人免费高清在线播放 | 亚洲一区二区三区四区在线播放 | 欧美男人天堂网 | 免费看黄色a级片 | 狠狠干天天色 | 久久久伦理片 | 精品福利影院 | 久久高清无码视频 | 美女av一区| 最新日韩精品 | 久青草视频在线观看 | 伊人av影院| 亚洲AV成人无码一二三区在线 | 亚洲在线免费视频 | 91大神在线观看视频 | 四虎影院新网址 | 亚洲天堂男人天堂 | www.成人| 毛片88 | 99成人精品| 91精品国产91综合久久蜜臀 | 国产xxxx18 | 蜜桃av鲁一鲁一鲁一鲁俄罗斯的 | 欧美日韩一区二区不卡 | 亚洲一区二区在线视频 | 精品无码久久久久久久久 | 爱啪啪网站 | 在线中文视频 | 成人乱人乱一区二区三区一级视频 | 国产精品啪 | 天堂中文在线视频 | 人体内射精一区二区三区 | 日韩欧美一区二区三区四区 | 免费在线国产精品 | 一级a毛片免费观看久久精品 | 久久天天躁狠狠躁夜夜躁2014 | 夜夜操夜夜骑 | 亚洲国产福利 | 精品一区二区三区四区五区 | 日韩免费淫片 | 亚欧洲精品 | 欧美成人免费在线 | 国产盗摄在线观看 | 国产一区二区三区在线视频观看 | 99精品网站 | 亚洲高清毛片一区二区 | 成人在线国产 | 小泽玛丽亚在线观看 | 福利社午夜 | 国产精品久久久久久久免费大片 | 国产91啪 | 中文字幕欧美另类精品亚洲 | 日韩3p | 夜夜爽日日澡人人添 | 精品中文视频 | 国产亚洲视频在线观看 | 福利在线免费视频 | 色性网| 日韩视频三区 | 污视频网址| 久久久久久日产精品 | 亚洲国产黄色av |