這篇文章主要介紹“什么是redis分布式鎖”,在日常操作中,相信很多人在什么是Redis分布式鎖問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”什么是Redis分布式鎖”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
創(chuàng)新互聯(lián)建站長期為近1000家客戶提供的網(wǎng)站建設服務,團隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務;打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為阿克塞哈薩克族自治企業(yè)提供專業(yè)的網(wǎng)站制作、成都網(wǎng)站設計,阿克塞哈薩克族自治網(wǎng)站改版等技術(shù)服務。擁有十載豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。
在分布式系統(tǒng)中,有些業(yè)務場景會用到分布式鎖,實現(xiàn)分布式鎖的方式有很多,本篇主要講根據(jù)Redis如何來實現(xiàn)。
首先我們要知道分布式鎖的一些基本特點:
互斥性:只有一個客戶端可以持有鎖
不會產(chǎn)生死鎖:即使持有鎖的客戶端崩潰,也能保證后續(xù)其他客戶端可以獲得鎖
只有持有這把鎖的客戶端才能解鎖
下邊我們通過幾個例子來說明分布式鎖為什么需要以上3個特點。
/** * 使用jedis客戶端實現(xiàn)分布式鎖 * @Author: maomao * @Date: 2021-04-27 08:42 */ public class DistLock { private static final String LOCK_SUCCESS = "OK"; private static final String SET_IF_NOT_EXIST = "NX"; private static final String SET_WITH_EXPIRE_TIME = "PX"; private static final Long RELEASE_SUCCESS = 1L; /** * 嘗試獲取分布式鎖 * @param jedis Redis客戶端 * @param lockKey 鎖 * @param value 值 * @param expireTime 超期時間 * @return 是否獲取成功 */ public static boolean tryGetDistributedLock(Jedis jedis, String value, String requestId, int expireTime) { // set支持多個參數(shù) NX(not exist) XX(exist) EX(seconds) PX(million seconds) String result = jedis.set(lockKey, value, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); if (LOCK_SUCCESS.equals(result)) { return true; } return false; } /** * 直接刪除解鎖,未判斷客戶端ID,會導致其他客戶端把鎖釋放 * @param jedis * @param lockKey */ public static void releaseLock1(Jedis jedis, String lockKey) { jedis.del(lockKey); } }
上邊代碼是一個不驗證客戶端的例子,加鎖是沒有問題的,但在解鎖時會有很大的問題。
通過上圖可以看到,因為沒有校驗客戶端邏輯,Thread B可以直接解鎖,而Thread A程序還未執(zhí)行完,但已被解鎖,造成鎖失效。如果此時有其他客戶端加鎖是可以加鎖成功的。
那我們可以在代碼中增加一個客戶端校驗不就可以了?
/** * 嘗試獲取分布式鎖 * @param jedis Redis客戶端 * @param lockKey 鎖 * @param requestId 請求標識-修改此處為客戶端唯一標致 * @param expireTime 超期時間 * @return 是否獲取成功 */ public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) { // set支持多個參數(shù) NX(not exist) XX(exist) EX(seconds) PX(million seconds) String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); if (LOCK_SUCCESS.equals(result)) { return true; } return false; } /** * 增加鎖判斷,但因判斷與刪除不是原子操作,在并發(fā)場景時,會導致錯誤刪除 * @param jedis * @param lockKey * @param requestId */ public static void releaseLock2(Jedis jedis, String lockKey, String requestId) { // 判斷加鎖與解鎖是不是同一個客戶端 if (requestId.equals(jedis.get(lockKey))) { // 若在此時,這把鎖突然不是這個客戶端的,則會誤解鎖 // 兩個操作不能保證原子性 jedis.del(lockKey); } }
在解鎖代碼中可以看到,我們也增加了客戶端標志校驗應該可以解決客戶端校驗問題了吧?其實并沒有,我們要知道對redis來說,每個命令都是原子的,你的get與del方法是兩個命令,無法保證原子操作。也就是我們多線程中常見的i++;操作,其實他是由3個操作執(zhí)行。
那我們?nèi)绾未_保get與del的原子操作呢?我們可以使用lua腳本來實現(xiàn)。上述代碼我們可以調(diào)整為一個lua腳本。
/** * 釋放分布式鎖,使用lua腳本刪除,可確保判斷與刪除的原子操作 * @param jedis Redis客戶端 * @param lockKey 鎖 * @param requestId 請求標識 * @return 是否釋放成功 */ public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); if (RELEASE_SUCCESS.equals(result)) { return true; } return false; }
通過增加客戶端校驗與解鎖的原子性就可以實現(xiàn)安全的解鎖。
有了上邊的方式是不是就可以確保分布式鎖的全部問題了?并不是,還有一種場景沒有考慮到。
如果我們的加鎖程序執(zhí)行時間超出鎖過期時間時,就會導致分布式鎖失效。此時其他客戶端是可以獲得到鎖的。如下圖:
那么這種問題如何解決呢?
Redisson是一個在Redis的基礎上實現(xiàn)的Java駐內(nèi)存數(shù)據(jù)網(wǎng)格(In-Memory Data Grid),提供了分布式和可擴展的Java數(shù)據(jù)結(jié)構(gòu),比如分布式對象,分布式集合(Map、List、Queue、Set),分布式鎖等等功能,不需要自己去運行一個服務實現(xiàn)。
Redisson官網(wǎng)
Redisson Git地址
Redission是由一個中國人與俄羅斯人共同發(fā)起的,所以中文文檔比較詳細。
使用Redission可以很簡單的實現(xiàn)分布式鎖,代碼如下:
public static void main(String[] args) throws InterruptedException { //設定鎖標志 //會在redis中創(chuàng)建一個Hash,Key是客戶端UUID,value是鎖重入次數(shù) RLock rLock = redissonClient.getLock("lockKey"); // 最多等待100秒、上鎖10s以后自動解鎖 if(rLock.tryLock(100,10, TimeUnit.SECONDS)){ System.out.println("獲取鎖成功,此時可以查看redis中的數(shù)據(jù)!"); } //線程等待后可在redis中查到 Thread.sleep(20000); rLock.unlock(); }
Redission不只可以實現(xiàn)獨占鎖,還可以實現(xiàn)如:可重入鎖、公平鎖、聯(lián)鎖、紅鎖、讀寫鎖等等。
redission實現(xiàn)分布式鎖的邏輯基本與上邊我們講的原理差不多,它還解決了我們最后一個問題,程序執(zhí)行時間超出鎖過期時間的問題。
他使用了一個《看門狗》的概念來實現(xiàn)自動續(xù)期。默認最大續(xù)期時間30s,也就是說如果業(yè)務超出30秒還未執(zhí)行會自動解鎖。
到此,關(guān)于“什么是Redis分布式鎖”的學習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
當前文章:什么是Redis分布式鎖
轉(zhuǎn)載來于:http://muchs.cn/article24/pjjgce.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供響應式網(wǎng)站、網(wǎng)站營銷、App設計、外貿(mào)建站、網(wǎng)站制作、微信小程序
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)