国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

使用redis實(shí)現(xiàn)分布式鎖

這篇具有很好參考價(jià)值的文章主要介紹了使用redis實(shí)現(xiàn)分布式鎖。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

為什么需要分布式鎖

在一個(gè)分布式系統(tǒng)中,也會涉及多個(gè)節(jié)點(diǎn)訪問同一個(gè)公共資源的情況,此時(shí)就需要通過鎖來做互斥控制,避免出現(xiàn)類似于“線程安全”的問題,而java的synchronized這樣的鎖只能在當(dāng)前進(jìn)程中生效,在分布式的這種多個(gè)進(jìn)程多個(gè)主機(jī)的場景無能為力,此時(shí)就需要分布式鎖。

分布式鎖的基礎(chǔ)實(shí)現(xiàn)

例如:買票場景,現(xiàn)在車站提供了若干車次,每個(gè)車次的票數(shù)都是固定的。現(xiàn)在又多個(gè)服務(wù)器節(jié)點(diǎn),都可能需要處理這個(gè)買票邏輯,先查詢指定車次的余票,如果余票>0,則設(shè)置余票值-=1.

使用redis實(shí)現(xiàn)分布式鎖,redis,分布式,redis
客戶端1先查詢余票,發(fā)現(xiàn)剩余1張,在即將執(zhí)行1->0過程之前;客戶端2也執(zhí)行查詢余票,發(fā)現(xiàn)也是剩余1張,也會執(zhí)行1->0過程。這就造成1張票賣了給兩個(gè)人,即超賣。
我們可以在上述架構(gòu)中引入redis,作為分布式鎖的管理器。
使用redis實(shí)現(xiàn)分布式鎖,redis,分布式,redis
所謂的分布式鎖,也是一個(gè)/一組單獨(dú)的服務(wù)器程序(如redis),給其他服務(wù)器提供“加鎖”服務(wù)。
買票服務(wù)器,在進(jìn)行買票操作的時(shí)候,需要先加鎖。往redis上設(shè)置一個(gè)特殊的鍵值對key-value,完成上述買票操作,再把這個(gè)key-value刪除掉。其他服務(wù)器也想去買票的時(shí)候,也去redis上嘗試設(shè)置key-value,如果發(fā)現(xiàn)key-value已經(jīng)存在,就認(rèn)為“加鎖失敗”(是放棄/阻塞等待,就看具體實(shí)現(xiàn))。這樣就可以保證,第一個(gè)服務(wù)器在執(zhí)行“查詢->更新"的過程中,第二個(gè)服務(wù)器不會執(zhí)行”查詢“,也就解決了”超賣“問題。
:::success
redis中提供的setnx操作,正好適合上述場景。即key不存在就設(shè)置,存在則設(shè)置失敗
:::

引入過期時(shí)間

某個(gè)服務(wù)器中加鎖成功后(setnx成功),如果該服務(wù)器意外發(fā)生宕機(jī),就會導(dǎo)致解鎖操作(刪除該key)不能執(zhí)行,就可能引起其他服務(wù)器始終無法獲取到鎖的情況。

在java的多線程編程中,可以把解鎖操作放到finally中,保證解鎖操作一定會被執(zhí)行到。但是這種做法只是針對進(jìn)程內(nèi)的鎖有用(進(jìn)程異常退出,鎖也就隨之銷毀)。而分布式鎖是無效的,服務(wù)器宕機(jī)以后會導(dǎo)致redis上設(shè)置的key無人刪除,也就導(dǎo)致其他服務(wù)器無法獲取到鎖

:::info
引入過期時(shí)間,使用set ex nx的方式,在設(shè)置鎖的同時(shí)把過期時(shí)間設(shè)置進(jìn)去,一但時(shí)間到了,key就會自動被刪除掉。
:::
注意!此處設(shè)置過期時(shí)間只能使用一個(gè)命令的方式設(shè)置。

如果分開設(shè)置,比如setnx之后,再來個(gè)expire。redis多個(gè)指令之間,無法保證原子性(redis的原子性是只能保證執(zhí)行,不能保證成功)。此時(shí)就可能出現(xiàn)這兩個(gè)命令,一個(gè)執(zhí)行成功,一個(gè)執(zhí)行失敗情況

引入校驗(yàn)id

對于redis中寫入的加鎖鍵值對,其他節(jié)點(diǎn)也是可以刪除的。

比如 服務(wù)器1寫入一個(gè)001:1這樣的鍵值對,服務(wù)器2是完全可以把001:1給刪除掉。當(dāng)然,服務(wù)器2一般不會這樣”惡意刪除“操作,不過不能保證因?yàn)橐恍゜ug導(dǎo)致服務(wù)器2把鎖給誤刪除

為了解決上述問題,我們可以引入一個(gè)校驗(yàn)id。

  1. 給服務(wù)器編號,每個(gè)服務(wù)器都有一個(gè)自己的身份標(biāo)識
  2. 進(jìn)行加鎖的時(shí)候,設(shè)置key-value。key是針對哪個(gè)資源加鎖(比如車次),value就可以存儲剛才服務(wù)器的編號,標(biāo)識出當(dāng)前這個(gè)鎖是哪個(gè)服務(wù)器加上的。
  3. 解鎖的時(shí)候,先查詢一下這個(gè)鎖對應(yīng)的服務(wù)器編號,然后判定一下value是否和當(dāng)前執(zhí)行解鎖的服務(wù)器編號一致,如果一致,才能真正執(zhí)行del,如果不是,就失敗。

偽代碼如下:

String key = [要加鎖的資源 id]; 
String serverId = [服務(wù)器的編號]; 
// 加鎖, 設(shè)置過期時(shí)間為 10s 
redis.set(key, serverId, "NX", "EX", "10s");  
// 執(zhí)?各種業(yè)務(wù)邏輯, ?如修改數(shù)據(jù)庫數(shù)據(jù). 
doSomeThing();
// 解鎖, 刪除 key. 但是刪除前要檢驗(yàn)下 serverId 是否匹配.
if (redis.get(key) == serverId) { 
	redis.del(key); 
}  

但是很明顯,在解鎖的時(shí)候,getdel是兩步操作,不是原子的。

引入lua

在服務(wù)器內(nèi)部,可能是多線程的。例如服務(wù)器1中有兩個(gè)線程都在執(zhí)行上述解鎖操作。
使用redis實(shí)現(xiàn)分布式鎖,redis,分布式,redis
在服務(wù)器1中,看起來只是重復(fù)執(zhí)行del操作,問題不大???但是當(dāng)服務(wù)器2,執(zhí)行加鎖時(shí),就可能出現(xiàn)問題了。
線程A執(zhí)行完del操作后,線程B執(zhí)行del操作之前,服務(wù)器2的線程C正好要執(zhí)行加鎖操作。此時(shí)線程A已經(jīng)把鎖刪除了,線程C是能夠加鎖成功的。但是緊接著,線程B就會執(zhí)行del操作,就會把服務(wù)器2的加鎖操作給解鎖了。雖然del操作中有引入校驗(yàn)id,但是線程B在get操作中已經(jīng)通過id校驗(yàn),可以執(zhí)行del操作,雖然線程C這把鎖的id不同,也能夠解鎖。
使用redis是事務(wù),能夠避免命令之間的插隊(duì)。但是實(shí)踐中往往是使用lua腳本。由于lua語言非常輕量,因此可以內(nèi)嵌到redis中。我們可以使用lua編寫一些邏輯,把這個(gè)腳本上傳到redis服務(wù)器上,然后就可以讓客服端來控制redis執(zhí)行上述腳本。redis執(zhí)行l(wèi)ua腳本的過程,是原子的。并且redis官方也明確說明,lua屬于事務(wù)的替代方案。
使用lua腳本實(shí)現(xiàn)上述解鎖功能:

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

使用redis實(shí)現(xiàn)分布式鎖,redis,分布式,redis

引入看門狗(watch dog)

上述方案中仍然存在一個(gè)重要問題,在加鎖的時(shí)候,需要給key設(shè)置過期時(shí)間。過期時(shí)間,設(shè)置多少合適呢?

  • 設(shè)置太短,就可能業(yè)務(wù)邏輯還沒執(zhí)行完,就釋放鎖
  • 設(shè)置太長,會導(dǎo)致”鎖釋放不及時(shí)“問題

因此更好的方式是”動態(tài)續(xù)約“,這就需要服務(wù)器這邊有一個(gè)專門的線程,負(fù)責(zé)續(xù)約這件事。我們把這個(gè)負(fù)責(zé)的線程,叫做”看門狗“(watch dog).

舉個(gè)具體的例子:
初始情況下設(shè)置過期時(shí)間10s,同時(shí)設(shè)定看門狗線程每隔3s檢測一次。
當(dāng)3s時(shí)間到的時(shí)候,看門狗就會判定當(dāng)前任務(wù)是否完成。

  • 如果任務(wù)已經(jīng)完成,直接通過lua腳本的方式,釋放鎖(刪除key)
  • 如果任務(wù)未完成,則把過期時(shí)間重新設(shè)置為10s,即續(xù)約

這樣就不用擔(dān)心鎖提前釋放的問題了,而且另外一方面,如果服務(wù)器掛了,看門狗線程也會被銷毀,此時(shí)無人續(xù)約,這個(gè)key自然就可以迅速過期,讓其他服務(wù)器獲取到鎖

引入redlock算法

實(shí)踐中的redis一般使用集群的方式部署的,那么就可能出現(xiàn)以下比較極端的情況。

服務(wù)器1向master節(jié)點(diǎn)進(jìn)行加鎖操作,這個(gè)寫入key的過程剛完成,master掛了;slave節(jié)點(diǎn)升級成新的master節(jié)點(diǎn),但是由于剛才寫入的這個(gè)key未來得及同步給slave,此時(shí)就相當(dāng)于服務(wù)器1的加鎖操作形同虛設(shè)。服務(wù)器2仍然可以進(jìn)行加鎖,即給新的master寫入key,因?yàn)樾碌膍aster不包含剛才的key。

為了解決這個(gè)問題,redis作者提出了redlock算法。本質(zhì)上是使用冗余解決可用性問題
使用redis實(shí)現(xiàn)分布式鎖,redis,分布式,redis
此處加鎖,就是按照一定的順序,針對redis集群的所有分片都進(jìn)行加鎖操作。如果某個(gè)節(jié)點(diǎn)掛了(加不上鎖了)繼續(xù)給下一個(gè)節(jié)點(diǎn)加鎖即可。如果寫入key成功的節(jié)點(diǎn)個(gè)數(shù)超過總數(shù)的一半,就視為加鎖成功。同理,進(jìn)行解鎖的時(shí)候,也就會把上述節(jié)點(diǎn)都設(shè)置一遍解鎖。文章來源地址http://www.zghlxwxcb.cn/news/detail-730373.html

到了這里,關(guān)于使用redis實(shí)現(xiàn)分布式鎖的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 使用 redis 實(shí)現(xiàn)分布式接口限流注解 RedisLimit

    使用 redis 實(shí)現(xiàn)分布式接口限流注解 RedisLimit

    前言 很多時(shí)候,由于種種不可描述的原因,我們需要針對單個(gè)接口實(shí)現(xiàn)接口限流,防止訪問次數(shù)過于頻繁。這里就用 redis+aop 實(shí)現(xiàn)一個(gè)限流接口注解 @RedisLimit 代碼 點(diǎn)擊查看RedisLimit注解代碼 AOP代碼 點(diǎn)擊查看aop代碼 lua腳本代碼 注意:腳本代碼是放在 resources 文件下的,它的類型是

    2024年02月08日
    瀏覽(23)
  • Zookeeper 和 Redis 哪種更好? 為什么使用分布式鎖? 1. 利用 Redis 提供的 第二種,基于 ZK 實(shí)現(xiàn)分布式鎖的落地方案 對于 redis 的分布式鎖而言,它有以下缺點(diǎn):

    關(guān)于這個(gè)問題,我們 可以從 3 個(gè)方面來說: 為什么使用分布式鎖? 使用分布式鎖的目的,是為了保證同一時(shí)間只有一個(gè) JVM 進(jìn)程可以對共享資源進(jìn)行操作。 根據(jù)鎖的用途可以細(xì)分為以下兩類: 允許多個(gè)客戶端操作共享資源,我們稱為共享鎖 這種鎖的一般是對共享資源具有

    2024年01月16日
    瀏覽(23)
  • 分布式鎖設(shè)計(jì)選型 不可重入鎖建議使用ZooKeeper來實(shí)現(xiàn) 可重入鎖建議使用Redis來實(shí)現(xiàn) 分布式鎖:ZooKeeper不可重入鎖 Java優(yōu)化建議

    在設(shè)計(jì)分布式鎖時(shí),需要考慮業(yè)務(wù)場景和業(yè)務(wù)需求,以保證鎖的正確性和可用性。 例如,在一個(gè)電商系統(tǒng)中,每個(gè)商品都有一個(gè)庫存量。為了避免多個(gè)用戶同時(shí)購買同一件商品導(dǎo)致庫存出現(xiàn)不一致的情況,可以為每個(gè)商品設(shè)置一個(gè)分布式鎖,確保同一時(shí)間只能有一個(gè)用戶購買

    2024年02月08日
    瀏覽(21)
  • 分布式鎖實(shí)現(xiàn)(mysql,以及redis)以及分布式的概念

    分布式鎖實(shí)現(xiàn)(mysql,以及redis)以及分布式的概念

    我旁邊的一位老哥跟我說,你知道分布式是是用來干什么的嘛?一句話給我干懵了,我能隱含知道,大概是用來做分壓處理的,并增加系統(tǒng)穩(wěn)定性的。但是具體如何,我卻道不出個(gè)1,2,3?,F(xiàn)在就將這些做一個(gè)詳細(xì)的總結(jié)。至少以后碰到面試官可以說上個(gè)123。 那么就正式進(jìn)入

    2024年01月21日
    瀏覽(37)
  • 在Spring中,可以使用不同的方式來實(shí)現(xiàn)分布式鎖,例如基于數(shù)據(jù)庫、Redis、ZooKeeper等

    在Spring中,可以使用不同的方式來實(shí)現(xiàn)分布式鎖,例如基于數(shù)據(jù)庫、Redis、ZooKeeper等

    在Spring中,可以使用不同的方式來實(shí)現(xiàn)分布式鎖,例如基于數(shù)據(jù)庫、Redis、ZooKeeper等。下面是兩種常見的實(shí)現(xiàn)方式: 使用Redis實(shí)現(xiàn)分布式鎖: 使用自定義注解實(shí)現(xiàn)本地鎖: 以上是兩種常見的在Spring中實(shí)現(xiàn)分布式鎖的方式。第一種方式使用Redis作為分布式鎖的存儲介質(zhì),通過

    2024年03月17日
    瀏覽(24)
  • Redis——》實(shí)現(xiàn)分布式鎖

    推薦鏈接: ????總結(jié)——》【Java】 ????總結(jié)——》【Mysql】 ????總結(jié)——》【Redis】 ????總結(jié)——》【Kafka】 ????總結(jié)——》【Spring】 ????總結(jié)——》【SpringBoot】 ????總結(jié)——》【MyBatis、MyBatis-Plus】 ????總結(jié)——》【Linux】 ????總結(jié)——》【MongoDB】 ???

    2024年02月10日
    瀏覽(24)
  • redis實(shí)現(xiàn)分布式延時(shí)隊(duì)列

    redis實(shí)現(xiàn)分布式延時(shí)隊(duì)列

    延時(shí)隊(duì)列是一種特殊的消息隊(duì)列,它允許將消息在一定的延遲時(shí)間后再進(jìn)行消費(fèi)。延時(shí)隊(duì)列的主要特點(diǎn)是可以延遲消息的處理時(shí)間,以滿足定時(shí)任務(wù)或者定時(shí)事件的需求。 總之,延時(shí)隊(duì)列通過延遲消息的消費(fèi)時(shí)間,提供了一種方便、可靠的方式來處理定時(shí)任務(wù)和定時(shí)事件。它

    2024年02月08日
    瀏覽(18)
  • Redis分布式鎖實(shí)現(xiàn)原理

    Redis分布式鎖實(shí)現(xiàn)原理

    在早期互聯(lián)網(wǎng)的架構(gòu)中,一個(gè)應(yīng)用都是單機(jī)進(jìn)行部署,這種情況下,利用JDK提供的鎖機(jī)制即可解決共享數(shù)據(jù)在多線程場景下的線程安全問題,但隨著技術(shù)的發(fā)展,分布式系統(tǒng)架構(gòu)逐漸普及,在分布式架構(gòu)中,由于一個(gè)應(yīng)用會進(jìn)行多機(jī)部署,服務(wù)器實(shí)例之間的JVM是互相獨(dú)立的,

    2024年02月16日
    瀏覽(16)
  • redis如何實(shí)現(xiàn)分布式鎖?

    首先,“分布式鎖”的概念,是相對“本地鎖”而言。 本地鎖比如java中的synchronized 這類 JDK 自帶的 本地鎖 ,來控制一個(gè) JVM 進(jìn)程內(nèi)的多個(gè)線程對本地共享資源的訪問。 同一時(shí)刻只有一個(gè)線程可以獲取到本地鎖訪問共享資源。 分布式系統(tǒng)下,不同的服務(wù)/客戶端通常運(yùn)

    2024年02月06日
    瀏覽(21)
  • 分布式鎖之redis實(shí)現(xiàn)

    分布式鎖之redis實(shí)現(xiàn)

    需要掛在的data和redis.conf自行創(chuàng)建即可 不要忘記開放端口6379 修改redis.conf配置文件,設(shè)置 requirepass xxxxx 如果直接使用RedisTemplate使用的序列化器是jdk的,存的是二進(jìn)制,使用StringRedisTemplate默認(rèn)初始化序列化器就是String類型 執(zhí)行票數(shù)存入redis指令 ?編寫代碼演示超賣問題 ?500

    2024年02月10日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包