本篇內(nèi)容主要講解“用redis實(shí)現(xiàn)分布式鎖的方案”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“用Redis實(shí)現(xiàn)分布式鎖的方案”吧!
創(chuàng)新互聯(lián)建站堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站建設(shè)、成都網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的寶安網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
在實(shí)際項(xiàng)目開發(fā)中經(jīng)常會(huì)遇到這樣一個(gè)業(yè)務(wù)場(chǎng)景:如果同一臺(tái)機(jī)器有多個(gè)線程搶奪同一個(gè)共享資源,同一個(gè)線程多次執(zhí)行會(huì)出現(xiàn)異常,這種情況下就會(huì)出現(xiàn)非線程安全。我們解決方法通常使用鎖來解決。但是如果有多臺(tái)機(jī)器呢?這時(shí)候我們通常使用分布式鎖來解決分布式環(huán)境下共享資源的同步問題。實(shí)現(xiàn)分布式鎖常見有Redis,zookeeper等,今天主要就是講講如何使用Redis實(shí)現(xiàn)分布式鎖。 使用Redis實(shí)現(xiàn)分布式鎖的方案其實(shí)很簡(jiǎn)單,首先我們先實(shí)現(xiàn)一個(gè)方案一:每次執(zhí)行請(qǐng)求的時(shí)候,機(jī)器先查詢Redis中是否存在分布式鎖的key,如果不存在鎖的key,就以該鎖為key,value取隨機(jī)數(shù)寫入到Redis中,然后開始執(zhí)行請(qǐng)求。 方案一看起來很簡(jiǎn)單,但是這樣的處理邏輯不可避免的存在兩個(gè)致命的BUG:第一:如果一個(gè)進(jìn)程成功取到鎖,但是這時(shí)候這個(gè)機(jī)器出現(xiàn)故障宕機(jī)了,分布式的鎖沒有得到釋放,就造成了死鎖的產(chǎn)生了。第二:如果同一時(shí)間存在兩個(gè)機(jī)器同時(shí)查詢Redis,都發(fā)現(xiàn)Redis不存在鎖的key,于是都成功獲得了鎖。 這時(shí)候我們可以這么處理改善方案一實(shí)現(xiàn)方案二:Redis有提供一個(gè)原子寫入操作的命令:setnx,setnx只有在鎖的key不存在的情況下才允許設(shè)置key值,所以說問題2同一個(gè)鎖在同一時(shí)間可能會(huì)被不同機(jī)器獲取到的問題就可以得到解決,而且setnx命令可以設(shè)置key值的超時(shí)時(shí)間,所以在寫入鎖的key時(shí)可以為鎖設(shè)置一個(gè)超時(shí)時(shí)間,如果超過超時(shí)時(shí)間鎖還未釋放就會(huì)釋放,則其他機(jī)器在key釋放后也可以繼續(xù)寫入key占有鎖執(zhí)行對(duì)應(yīng)的請(qǐng)求。這樣問題1機(jī)器宕機(jī)造成鎖無法及時(shí)釋放的問題也因此迎刃而解。 但是這又造成了另外一個(gè)潛在的問題:如果某個(gè)機(jī)器執(zhí)行耗時(shí)操作,超時(shí)時(shí)間過去了請(qǐng)求還未執(zhí)行完,鎖就會(huì)被釋放掉被新的機(jī)器占有,等耗時(shí)任務(wù)結(jié)束時(shí)執(zhí)行釋放鎖的操作,這時(shí)候釋放的鎖不是自己的鎖而是已經(jīng)被其他機(jī)器占有的鎖。 這時(shí)候我們可以將方案再做適當(dāng)?shù)男薷淖兂煞桨溉寒?dāng)某個(gè)機(jī)器占有鎖并在Redis中設(shè)置key時(shí),將value設(shè)置為隨機(jī)數(shù),在請(qǐng)求處理完畢需要釋放鎖之前加上一步操作:判斷key的value值是否等于之前設(shè)置的隨機(jī)數(shù),如果是代表這個(gè)鎖占有者還是自己,就可以執(zhí)行釋放鎖操作,否則代表鎖已經(jīng)被別人占有,不能執(zhí)行釋放鎖操作,這樣就可以解決可能誤操作釋放他人鎖的問題。但是由于查詢和釋放鎖的操作非原子性的,所以可能出現(xiàn)一種情況:在查詢key時(shí)發(fā)現(xiàn)key的value和機(jī)器本身設(shè)置的一直,但是還沒來得急釋放鎖時(shí),鎖過期被釋放了,這時(shí)候執(zhí)行釋放鎖操作就會(huì)導(dǎo)致釋放的依舊是其他機(jī)器占有的鎖,所以我們方案三需要進(jìn)一步的改進(jìn),也就是我們必須要保證查詢鎖和釋放鎖這兩步操作必須是原子性的,這時(shí)候我們就需要使用另一種方式:引入Jedis,使用Lua腳本將查詢鎖和釋放鎖的兩部分邏輯寫成腳本,于是Redis執(zhí)行Lua腳本時(shí),其他機(jī)器的所有命令都必須等到Lua腳本執(zhí)行結(jié)束才能執(zhí)行,所以不可能存在查詢鎖結(jié)束還未釋放就被其他機(jī)器占領(lǐng)的情況。
到這里我們介紹完了如何使用Redis實(shí)現(xiàn)分布式鎖,但是這是基于單機(jī)部署,如果Redis是使用多機(jī)部署,每個(gè)主節(jié)點(diǎn)還有有子節(jié)點(diǎn),由于Redis主從復(fù)制是異步操作,所在上述方案肯定會(huì)出現(xiàn)問題的,多機(jī)部署可以采用Redission實(shí)現(xiàn)分布式鎖,這是官方提供的組件,如果感興趣可以自己閱讀下文檔:
https://github.com/redisson/redisson
到此,相信大家對(duì)“用Redis實(shí)現(xiàn)分布式鎖的方案”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
分享文章:用Redis實(shí)現(xiàn)分布式鎖的方案
轉(zhuǎn)載來源:
http://weahome.cn/article/gcjdsd.html