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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

程序员修神之路--redis做分布式锁可能不那么简单

發(fā)布時(shí)間:2023/12/4 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 程序员修神之路--redis做分布式锁可能不那么简单 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
點(diǎn)擊上方“藍(lán)字”帶你去看小星星

菜菜哥,復(fù)聯(lián)四上映了,要不要一起去看看?

又想騙我電影票,對不對?

呵呵,想去看了叫我呀

看來你工作不飽和呀

哪有,這兩天我剛基于redis寫了一個(gè)分布式鎖,很簡單

不管你基于什么做分布式鎖,你覺得很簡單嗎?來來來


在計(jì)算機(jī)世界里,對于鎖大家并不陌生,在現(xiàn)代所有的語言中幾乎都提供了語言級別鎖的實(shí)現(xiàn),為什么我們的程序有時(shí)候會(huì)這么依賴鎖呢?這個(gè)問題還是要從計(jì)算機(jī)的發(fā)展說起,隨著計(jì)算機(jī)硬件的不斷升級,多核cpu,多線程,多通道等技術(shù)把計(jì)算機(jī)的計(jì)算速度大幅度提升,原來同一時(shí)間只能執(zhí)行一條cpu指令的時(shí)代已經(jīng)過去。隨著多條cpu指令可以并行執(zhí)行的原因,原來不曾出現(xiàn)的資源競爭隨著出現(xiàn),在程序中的體現(xiàn)就是隨處可見的多線程環(huán)境。比如要更新數(shù)據(jù)庫的一個(gè)信息,如果沒有并發(fā)控制,多個(gè)線程同時(shí)操作的話,就會(huì)出現(xiàn)互相覆蓋的現(xiàn)象發(fā)生。


鎖要解決的就是資源競爭的問題,也就是要把執(zhí)行的指令順序化


01為什么需要分布式鎖


隨著互聯(lián)網(wǎng)的興起,現(xiàn)代軟件發(fā)生了翻天覆地的變化,以前單機(jī)的程序,已經(jīng)支撐不了現(xiàn)代的業(yè)務(wù)。無論是在抗壓,還是在高可用等方面都需要多臺計(jì)算機(jī)協(xié)同工作來解決問題。現(xiàn)代的互聯(lián)網(wǎng)系統(tǒng)都是分布式部署的,分布式部署確實(shí)能帶來性能和效率上的提升,但為此,我們就需要多解決一個(gè)分布式環(huán)境下,數(shù)據(jù)一致性的問題。

當(dāng)某個(gè)資源在多系統(tǒng)之間共享的時(shí)候,為了保證大家訪問這個(gè)資源數(shù)據(jù)是一致的,那么就必須要求在同一時(shí)刻只能被一個(gè)客戶端處理,不能并發(fā)的執(zhí)行,否則就會(huì)出現(xiàn)同一時(shí)刻有人寫有人讀,大家訪問到的數(shù)據(jù)就不一致了。

在分布式系統(tǒng)的時(shí)代,傳統(tǒng)線程之間的鎖機(jī)制,就沒作用了,系統(tǒng)會(huì)有多份并且部署在不同的機(jī)器上,這些資源已經(jīng)不是在線程之間共享了,而是屬于進(jìn)程(服務(wù)器)之間共享的資源。

因此,為了解決這個(gè)問題,我們就必須引入「分布式鎖」。分布式鎖,是指在分布式的部署環(huán)境下,通過鎖機(jī)制來讓多客戶端互斥的對共享資源進(jìn)行訪問。分布式鎖的特點(diǎn)如下:

1互斥性和我們本地鎖一樣互斥性是最基本,但是分布式鎖需要保證在不同節(jié)點(diǎn)的不同線程的互斥。2可重入性同一個(gè)節(jié)點(diǎn)上的同一個(gè)線程如果獲取了鎖之后那么也可以再次獲取這個(gè)鎖。3鎖超時(shí)和本地鎖一樣支持鎖超時(shí),防止死鎖。4高效,高可用加鎖和解鎖需要高效,同時(shí)也需要保證高可用防止分布式鎖失效,可以增加降級。5支持阻塞和非阻塞和 ReentrantLock 一樣支持 lock 和 trylock 以及 tryLock(long timeOut)。


02基于redis分布式鎖


如果你通過網(wǎng)絡(luò)搜索分布式鎖,最多的就是基于redis的了。基于redis的分布式鎖得益于redis的單線程執(zhí)行機(jī)制,單線程在執(zhí)行上就保證了指令的順序化,所以很大程度上降低了開發(fā)人員的思考設(shè)計(jì)成本。但是,基于redis做分布式鎖難道真的這么容易嗎?


1原子操作


基于redis的分布式鎖常用命令是

SETNX?key?value


只在鍵 key 不存在的情況下,將鍵 key的值設(shè)置為value 。若鍵key 已經(jīng)存在, 則SETNX 命令不做任何動(dòng)作。SETNX 是『SET if Not eXists』(如果不存在,則 SET)的簡寫。代碼示例:

redis>?SETNX?redislock?"redislock"????#?redislock?設(shè)置成功
(integer)?1

redis>?SETNX?redislock?"redislock2"???#?嘗試覆蓋?redislock?,失敗
(integer)?0

redis>?GET?redislock???????????????????#?沒有被覆蓋
"redislock"


????????成功獲取到鎖之后,然后設(shè)置一個(gè)過期時(shí)間(這里避免了客戶端down掉,鎖得不到釋放的問題)

redis>?expire?redislock?5


成功拿到鎖的客戶端順利進(jìn)行自己的業(yè)務(wù),業(yè)務(wù)代碼執(zhí)行完,然后再刪除該key

redis>?DEL?redislock


如果一切都想想象的那么順利,程序員TMD就不用996了。假如客戶端拿到鎖之后,執(zhí)行設(shè)置超時(shí)指令之前down掉了(現(xiàn)實(shí)總是那么悲劇),那這個(gè)鎖就永遠(yuǎn)都釋放不了.也許你會(huì)想到用 Redis 事務(wù)來解決。但是這里不行,因?yàn)?expire 是依賴于 setnx 的執(zhí)行結(jié)果的,如果 setnx 沒搶到鎖,expire 是不應(yīng)該執(zhí)行的。事務(wù)里沒有 if-else 分支邏輯,事務(wù)的特點(diǎn)是一口氣執(zhí)行,要么全部執(zhí)行要么一個(gè)都不執(zhí)行。公司幾個(gè)億的業(yè)務(wù)又被你耽誤了...

????????以上情況的出現(xiàn)是因?yàn)閮蓚€(gè)命令并非一個(gè)原子性操作,所以在redis 2.8 版本之后出現(xiàn)了新的命令

SETEX?key?seconds?value


所以現(xiàn)在可以利用一條原子性操作的命令來獲取鎖

redis>?SETEX?redislock?60?redislock
OK

redis>
?GET?redislock??#?值
"redislock"

redis>
?TTL?redislock??#?剩余生存時(shí)間
(integer)?49


2超時(shí)問題


在正常的業(yè)務(wù)當(dāng)中,當(dāng)一個(gè)線程獲取到鎖并且設(shè)置了鎖的過期時(shí)間之后,會(huì)出現(xiàn)由于業(yè)務(wù)代碼執(zhí)行時(shí)間過長,鎖由于到達(dá)超時(shí)時(shí)間自動(dòng)釋放的情況。自動(dòng)釋放之后,其他的線程就會(huì)獲取到分布式鎖,導(dǎo)致業(yè)務(wù)代碼不會(huì)串行執(zhí)行。如果業(yè)務(wù)上允許這樣的情況偶爾發(fā)生,那程序員就開干吧,最后頂多人工干預(yù)一下,update 一下數(shù)據(jù)庫。

為了避免這類情況發(fā)生,在使用redis分布式鎖的時(shí)候,業(yè)務(wù)方應(yīng)盡量避免長時(shí)間執(zhí)行的代碼任務(wù)。

? ? ? ?如果設(shè)置鎖的超時(shí)時(shí)間比較長,在一定程度上可以緩解業(yè)務(wù)代碼執(zhí)行時(shí)間長鎖自動(dòng)到期的問題,但是一旦業(yè)務(wù)代碼down掉,其他等待鎖的線程等待的時(shí)間會(huì)比較長,這種情況下,確保獲取到鎖的程序不會(huì)down 成為了主要問題。


3獲取鎖失敗


當(dāng)鎖被一個(gè)調(diào)用方獲取之后,其他調(diào)用方在獲取鎖失敗之后,是繼續(xù)輪詢還是直接業(yè)務(wù)失敗呢?如果是繼續(xù)輪詢的話,同步情況下當(dāng)前線程會(huì)一直處于阻塞狀態(tài),所以這里輪詢的情況還是建議使用異步。


4可重入性


可重入性是指已經(jīng)擁有鎖的客戶端再次請求加鎖,如果鎖支持同一個(gè)客戶端重復(fù)加鎖,那么這個(gè)鎖就是可重入的。如果基于redis的分布式鎖要想支持可重入性,需要客戶端封裝,可以使用threadlocal存儲持有鎖的信息。這個(gè)封裝過程會(huì)增加代碼的復(fù)雜度,所以菜菜不推薦這樣做。


5redis掛了


如果在多個(gè)客戶端獲取鎖的過程中,redis 掛了怎么辦呢?假如一個(gè)客戶端已經(jīng)獲取到了鎖,這個(gè)時(shí)候redis掛了(假如是redis集群),其他的redis服務(wù)器會(huì)接著提供服務(wù),這個(gè)時(shí)候其他客戶端可以在新的服務(wù)器上獲取到鎖了,這也導(dǎo)致了鎖意義的丟失。有興趣的同學(xué)可以去看看RedLock,這種方案以犧牲性能的代價(jià)解決了這個(gè)問題。


6時(shí)鐘跳躍問題


在某些時(shí)候,redis的服務(wù)器時(shí)間發(fā)生的跳躍,由于鎖的過期時(shí)間依賴于服務(wù)器時(shí)間,所以也會(huì)出現(xiàn)兩個(gè)客戶端同時(shí)獲取到鎖的情況發(fā)生。


當(dāng)把以上問題都有解決方案了之后,基于redis的分布式鎖才可以放心使用


基于redis設(shè)計(jì)簡單分布式鎖容易,但是設(shè)計(jì)完美分布式鎖不易, 還覺得基于redis的分布式鎖好做嗎?




●程序員修神之路--問世間異步為何物?●程序員修神之路--提高網(wǎng)站的吞吐量?●程序員修神之路--?分布式高并發(fā)下Actor模型如此優(yōu)秀?●程序員過關(guān)斬將--論商品促銷代碼的優(yōu)雅性●程序員過關(guān)斬將--請不要隨便修改基類●程序員過關(guān)斬將--你的面向接口編程一定對嗎?●程序員修神之路--高并發(fā)下為什么更喜歡進(jìn)程內(nèi)緩存●程序員修神之路--高并發(fā)優(yōu)雅的做限流

架構(gòu)師之路,菜菜與君一起成長

長按識別二維碼關(guān)注

總結(jié)

以上是生活随笔為你收集整理的程序员修神之路--redis做分布式锁可能不那么简单的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。