溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

基于Redis緩存怎么實(shí)現(xiàn)分布式鎖

發(fā)布時(shí)間:2021-12-27 16:53:30 來(lái)源:億速云 閱讀:180 作者:iii 欄目:大數(shù)據(jù)

本篇內(nèi)容介紹了“基于Redis緩存怎么實(shí)現(xiàn)分布式鎖”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

什么是分布式鎖

首先我們先來(lái)簡(jiǎn)單了解一下什么是分布式鎖。

在引入分布式鎖之前大家應(yīng)該都知道經(jīng)典的 CAP 理論提到任何一個(gè)系統(tǒng)都無(wú)法同時(shí)滿足一致性(Consistency)、可用性(Availability)和分區(qū)容錯(cuò)性(Partition tolerance)三者的,同一時(shí)刻只能滿足兩個(gè),在這種情況下分布式鎖就出現(xiàn)了,分布式鎖就是用來(lái)解決數(shù)據(jù)一致性問(wèn)題的。

在以前單體應(yīng)用的環(huán)境下,Java 的 API 提供了很多控制并發(fā)的接口,包括 synchronized 以及 JUC 下面的一些實(shí)現(xiàn),但是在分布式環(huán)境下這些 API 就沒(méi)有用武之地了,因?yàn)閼?yīng)用是多實(shí)例部署的,很多實(shí)例甚至都不在同一臺(tái)主機(jī)上,根本無(wú)法使用 Java 中的 API,這個(gè)時(shí)候分布式鎖就誕生了。

所以簡(jiǎn)單說(shuō)什么是分布式鎖,分布式鎖就是在分布式環(huán)境下用來(lái)解決多實(shí)例對(duì)數(shù)據(jù)訪問(wèn)一致性的一種技術(shù)方案。

使用場(chǎng)景

在實(shí)際環(huán)境中我們有很多場(chǎng)景會(huì)用到分布式鎖,例如全局計(jì)數(shù)器,只要涉及到多個(gè)實(shí)例進(jìn)程對(duì)同一份數(shù)據(jù)進(jìn)行修改等操作都會(huì)需要分布式鎖。在比如在下單,更新緩存,減少庫(kù)存等場(chǎng)景下也會(huì)用到分布式鎖的。

分布式鎖的特性

在看分布式鎖的實(shí)現(xiàn)之前,我們先了解下一個(gè)分布式鎖應(yīng)該具備哪些特性:

  1. 在分布式環(huán)境下同一時(shí)刻只能被單個(gè)線程獲取;

  2. 可重入,意思是已經(jīng)獲得鎖的線程在執(zhí)行的過(guò)程中不需要再次獲得鎖;

  3. 異常或者超時(shí)自動(dòng)刪除,避免死鎖;

  4. 高性能,分布式環(huán)境下必須要性能好;

實(shí)現(xiàn)方式

分布式鎖的實(shí)現(xiàn)方式流行的主要有三種,分別是基于緩存 Redis 的實(shí)現(xiàn)方式,基于 ZK 臨時(shí)順序節(jié)點(diǎn)的實(shí)現(xiàn)以及基于數(shù)據(jù)庫(kù)行鎖的實(shí)現(xiàn)。這里簡(jiǎn)單提供下實(shí)現(xiàn)思路,不重復(fù)造輪子因?yàn)榫W(wǎng)上已經(jīng)有很多開(kāi)源的很好的解決方案了。

基于 Redis 緩存的實(shí)現(xiàn)

首先我們來(lái)看下基于 Redis 緩存實(shí)現(xiàn)的分布式鎖,Redis 支持 SETNX 命令,表示設(shè)置一個(gè) key 的值當(dāng)且進(jìn)度 Key 不存在的時(shí)候才能設(shè)置成功。例如執(zhí)行如下命令:set ziyou 18 NX PX 10000 表示將名叫 ziyou 的 key 的值設(shè)置為 18,當(dāng)且僅當(dāng)不存在名為 ziyou 的 key 的時(shí)候才能設(shè)置成功,并且過(guò)期時(shí)間設(shè)置為 10 秒鐘。

setnx 命令是 Redis 實(shí)現(xiàn)分布式鎖的核心,這個(gè)命令操作是原子操作的,千萬(wàn)不能分兩步先用 set 再用 expire,這樣分開(kāi)操作不是原子性的,無(wú)法實(shí)現(xiàn)效果。

然后 Redis 分布式鎖在網(wǎng)上有開(kāi)源實(shí)現(xiàn) [Redission](https://github.com/redisson/redisson),具體的實(shí)現(xiàn)可以參考。

百度也有一個(gè)開(kāi)源的分布式 Redis 鎖叫 [dlock](https://github.com/baidu/dlock),我們采用就是這個(gè),目前使用這么久還沒(méi)出現(xiàn)什么問(wèn)題。使用方式類似下面:

基于Redis緩存怎么實(shí)現(xiàn)分布式鎖

優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

1. 實(shí)現(xiàn)簡(jiǎn)單;

2. 理解邏輯簡(jiǎn)單;

3. 性能好,畢竟是緩存。

缺點(diǎn):

1. Redis 容易單點(diǎn)故障,集群部署;

2. key 的過(guò)期時(shí)間設(shè)置多少不明確,只能根據(jù)實(shí)際情況調(diào)整。


基于 ZK 的實(shí)現(xiàn)

前面提到 Redis 的核心的是 SETNX 命令,那么對(duì)于 ZK 來(lái)說(shuō),實(shí)現(xiàn)分布式鎖的核心是臨時(shí)順序節(jié)點(diǎn)。首先關(guān)于 ZK 的知識(shí)我們后面有機(jī)會(huì)再跟大家介紹,目前我們只要知道 ZK 的節(jié)點(diǎn)種類中有一種叫做臨時(shí)順序節(jié)點(diǎn),兩個(gè)關(guān)鍵詞:臨時(shí),順序。

臨時(shí)表示在客戶端創(chuàng)建某節(jié)點(diǎn)后,如果客戶端經(jīng)過(guò)一段時(shí)間跟服務(wù)端之間失去了心跳,說(shuō)明客戶端已經(jīng)掉線了,那么這個(gè)節(jié)點(diǎn)就會(huì)被自動(dòng)刪除(這一點(diǎn)跟 Redis key 的過(guò)期時(shí)間類似);順序的意思是在一個(gè) node 下面生成的子節(jié)點(diǎn)是按順序的,每個(gè)子節(jié)點(diǎn)都有一個(gè)唯一編號(hào),并且這個(gè)編號(hào)是按順序自增的。

臨時(shí)順序節(jié)點(diǎn)再加上 ZK 的監(jiān)聽(tīng)機(jī)制就可以實(shí)現(xiàn)分布式鎖了,Curator 是一個(gè) ZK 的開(kāi)源客戶端,也提供了分布式鎖的實(shí)現(xiàn),這個(gè)我沒(méi)用實(shí)際用過(guò),但是網(wǎng)上用的人也很多,大家可以自己去研究一下。

優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

1. ZK 本身就是集群部署,避免單機(jī)故障;

2. 順序節(jié)點(diǎn)所以不用考慮過(guò)期時(shí)間設(shè)置問(wèn)題;

缺點(diǎn):

1. 實(shí)現(xiàn)較為復(fù)雜;

2. 非緩存機(jī)制,大量頻繁創(chuàng)建刪除節(jié)點(diǎn)會(huì)影響 ZK 集群性能;

基于數(shù)據(jù)庫(kù)的實(shí)現(xiàn)

基于數(shù)據(jù)庫(kù)的分布式鎖個(gè)人覺(jué)得性能不是很好,在高并發(fā)的情況下對(duì)數(shù)據(jù)庫(kù)服務(wù)器的壓力過(guò)大,會(huì)影響業(yè)務(wù),不建議使用。不過(guò)從學(xué)習(xí)的角度來(lái)看,我們還是有必要了解下具體的實(shí)現(xiàn)方式?;跀?shù)據(jù)庫(kù)的分布式鎖的實(shí)現(xiàn)大致有兩種方式,這里的數(shù)據(jù)庫(kù)我們以 MySQL 為例。兩種方案的實(shí)現(xiàn)都需要一個(gè)額外的表,并且要有一個(gè)唯一索引字段。

1. 阻塞式語(yǔ)句  select xxx for update 

2. 非阻塞試  insert into xxx ; delete from

解釋下:

第一種方案在實(shí)施的時(shí)候,需要關(guān)閉事務(wù)的自動(dòng)提交,然后執(zhí)行 SQL 去獲得鎖,如果獲得鎖成功,執(zhí)行下面的業(yè)務(wù)邏輯,如果這里沒(méi)有獲取到鎖,則會(huì)阻塞,一直等待。業(yè)務(wù)執(zhí)行結(jié)束后,手動(dòng)提交事務(wù)。這里如果程序在執(zhí)行提交事務(wù)失敗,異?;蛘叻?wù)宕機(jī)后,數(shù)據(jù)庫(kù)會(huì)自動(dòng)釋放鎖,以免導(dǎo)致死鎖。但是這里有個(gè)問(wèn)題就是如果在高并發(fā)的情況下,很多線程都沒(méi)有獲得到鎖,都在阻塞等待,這樣會(huì)導(dǎo)致數(shù)據(jù)庫(kù)的服務(wù)器壓力過(guò)大,會(huì)影響數(shù)據(jù)庫(kù)的服務(wù)。這個(gè)是要注意的,這也是我不建議的地方,容易出現(xiàn)瓶頸,畢竟沒(méi)有緩存高效。

第二種方案跟第一種類似,不一樣的地方是這里通過(guò)第一步向指定的表中插入一條唯一索引的數(shù)據(jù),插入成功則表示獲得鎖,插入失敗則未獲得到鎖,成功獲得的鎖后就可以執(zhí)行業(yè)務(wù)邏輯,在執(zhí)行完業(yè)務(wù)邏輯后就可以刪除執(zhí)行的記錄。如果插入失敗就需要重新觸發(fā)獲取鎖的動(dòng)作。但是這種方案存在的問(wèn)題是無(wú)法設(shè)置鎖的失效時(shí)間,需要其他手段來(lái)清理超時(shí)數(shù)據(jù),而且為了支持可重入,需要將主機(jī)和服務(wù)的信息一起保存。

優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

1. 容易理解和實(shí)現(xiàn),但是細(xì)節(jié)要注意;

缺點(diǎn):

1. 高并發(fā)的情況下性能不好,阻塞式的情況下很多鏈接不釋放會(huì)拖垮數(shù)據(jù)庫(kù)服務(wù);

2. 需要定時(shí)清理超時(shí)數(shù)據(jù),麻煩;

3. 數(shù)據(jù)庫(kù)的行鎖會(huì)因?yàn)?MySQL 的查詢優(yōu)化而失效

“基于Redis緩存怎么實(shí)現(xiàn)分布式鎖”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI