淺析Redis中紅鎖RedLock的實(shí)現(xiàn)原理
RedLock 是一種分布式鎖的實(shí)現(xiàn)算法,由 Redis 的作者 Salvatore Sanfilippo(也稱為 Antirez)提出,主要用于解決在分布式系統(tǒng)中實(shí)現(xiàn)可靠鎖的問題。在 Redis 單獨(dú)節(jié)點(diǎn)的基礎(chǔ)上,RedLock 使用了多個(gè)獨(dú)立的 Redis 實(shí)例(通常建議是奇數(shù)個(gè),比如 5 個(gè)),共同協(xié)作來提供更強(qiáng)健的分布式鎖服務(wù)。
RedLock 算法旨在解決單個(gè) Redis 實(shí)例作為分布式鎖時(shí)可能出現(xiàn)的單點(diǎn)故障問題,通過在多個(gè)獨(dú)立運(yùn)行的 Redis 實(shí)例上同時(shí)獲取鎖的方式來提高鎖服務(wù)的可用性和安全性。
RedLock 具備以下主要特性:
- 互斥性:在任何時(shí)間,只有一個(gè)客戶端可以獲得鎖,確保了資源的互斥訪問。
- 避免死鎖:通過為鎖設(shè)置一個(gè)較短的過期時(shí)間,即使客戶端在獲得鎖后由于網(wǎng)絡(luò)故障等原因未能按時(shí)釋放鎖,鎖也會(huì)因?yàn)檫^期而自動(dòng)釋放,避免了死鎖的發(fā)生。
- 容錯(cuò)性:即使一部分 Redis 節(jié)點(diǎn)宕機(jī),只要大多數(shù)節(jié)點(diǎn)(即過半數(shù)以上的節(jié)點(diǎn))仍在線,RedLock 算法就能繼續(xù)提供服務(wù),并確保鎖的正確性。
1.RedLock 實(shí)現(xiàn)思路
RedLock 是對(duì)集群的每個(gè)節(jié)點(diǎn)進(jìn)行加鎖,如果大多數(shù)節(jié)點(diǎn)(N/2+1)加鎖成功,則才會(huì)認(rèn)為加鎖成功。
這樣即使集群中有某個(gè)節(jié)點(diǎn)掛掉了,因?yàn)榇蟛糠旨汗?jié)點(diǎn)都加鎖成功了,所以分布式鎖還是可以繼續(xù)使用的。
2.工作流程
RedLock 算法的工作流程大致如下:
- 客戶端向多個(gè)獨(dú)立的 Redis 實(shí)例嘗試獲取鎖,設(shè)置鎖的過期時(shí)間非常短。
- 如果客戶端能在大部分節(jié)點(diǎn)上成功獲取鎖,并且所花費(fèi)的時(shí)間小于鎖的過期時(shí)間的一半,那么認(rèn)為客戶端成功獲取到了分布式鎖。
- 當(dāng)客戶端完成對(duì)受保護(hù)資源的操作后,它需要向所有曾獲取鎖的 Redis 實(shí)例釋放鎖。
- 若在釋放鎖的過程中,客戶端因故無法完成,由于設(shè)置了鎖的過期時(shí)間,鎖最終會(huì)自動(dòng)過期釋放,避免了死鎖。
3.基本使用
在 Java 開發(fā)中,可以使用 Redisson 框架很方便的實(shí)現(xiàn) RedLock,具體操作代碼如下:
import org.redisson.Redisson;
import org.redisson.api.RedisClient;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.redisson.RedissonRedLock;
public class RedLockDemo {
public static void main(String[] args) {
// 創(chuàng)建 Redisson 客戶端配置
Config config = new Config();
config.useClusterServers()
.addNodeAddress("redis://127.0.0.1:6379",
"redis://127.0.0.1:6380",
"redis://127.0.0.1:6381"); // 假設(shè)有三個(gè) Redis 節(jié)點(diǎn)
// 創(chuàng)建 Redisson 客戶端實(shí)例
RedissonClient redissonClient = Redisson.create(config);
// 創(chuàng)建 RedLock 對(duì)象
RedissonRedLock redLock = redissonClient.getRedLock("resource");
try {
// 嘗試獲取分布式鎖,最多嘗試 5 秒獲取鎖,并且鎖的有效期為 5000 毫秒
boolean lockAcquired = redLock.tryLock(5, 5000, TimeUnit.MILLISECONDS);
if (lockAcquired) {
// 加鎖成功,執(zhí)行業(yè)務(wù)代碼...
} else {
System.out.println("Failed to acquire the lock!");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("Interrupted while acquiring the lock");
} finally {
// 無論是否成功獲取到鎖,在業(yè)務(wù)邏輯結(jié)束后都要釋放鎖
if (redLock.isLocked()) {
redLock.unlock();
}
// 關(guān)閉 Redisson 客戶端連接
redissonClient.shutdown();
}
}
}
4.實(shí)現(xiàn)原理
Redisson 中的 RedLock 是基于 RedissonMultiLock(聯(lián)鎖)實(shí)現(xiàn)的。
RedissonMultiLock 是 Redisson 提供的一種分布式鎖類型,它可以同時(shí)操作多個(gè)鎖,以達(dá)到對(duì)多個(gè)鎖進(jìn)行統(tǒng)一管理的目的。聯(lián)鎖的操作是原子性的,即要么全部鎖住,要么全部解鎖。這樣可以保證多個(gè)鎖的一致性。
RedissonMultiLock 使用示例如下:
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.multi.MultiLock;
public class RedissonMultiLockDemo {
public static void main(String[] args) throws InterruptedException {
// 創(chuàng)建 Redisson 客戶端
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redisson = Redisson.create(config);
// 創(chuàng)建多個(gè)分布式鎖實(shí)例
RLock lock1 = redisson.getLock("lock1");
RLock lock2 = redisson.getLock("lock2");
RLock lock3 = redisson.getLock("lock3");
// 創(chuàng)建 RedissonMultiLock 對(duì)象
MultiLock multiLock = new MultiLock(lock1, lock2, lock3);
// 加鎖
multiLock.lock();
try {
// 執(zhí)行任務(wù)
System.out.println("Lock acquired. Task started.");
Thread.sleep(3000);
System.out.println("Task finished. Releasing the lock.");
} finally {
// 釋放鎖
multiLock.unlock();
}
// 關(guān)閉客戶端連接
redisson.shutdown();
}
}
在示例中,我們首先創(chuàng)建了一個(gè) Redisson 客戶端并連接到 Redis 服務(wù)器。然后,我們使用 redisson.getLock 方法創(chuàng)建了多個(gè)分布式鎖實(shí)例。接下來,我們通過傳入這些鎖實(shí)例來創(chuàng)建了 RedissonMultiLock 對(duì)象。
說回正題,RedissonRedLock 是基于 RedissonMultiLock 實(shí)現(xiàn)的這點(diǎn),可以從繼承關(guān)系看出。
RedissonRedLock 繼承自 RedissonMultiLock,核心實(shí)現(xiàn)源碼如下:
public class RedissonRedLock extends RedissonMultiLock {
public RedissonRedLock(RLock... locks) {
super(locks);
}
/**
* 鎖可以失敗的次數(shù),鎖的數(shù)量-鎖成功客戶端最小的數(shù)量
*/
@Override
protected int failedLocksLimit() {
return locks.size() - minLocksAmount(locks);
}
/**
* 鎖的數(shù)量 / 2 + 1,例如有3個(gè)客戶端加鎖,那么最少需要2個(gè)客戶端加鎖成功
*/
protected int minLocksAmount(final List<RLock> locks) {
return locks.size()/2 + 1;
}
/**
* 計(jì)算多個(gè)客戶端一起加鎖的超時(shí)時(shí)間,每個(gè)客戶端的等待時(shí)間
*/
@Override
protected long calcLockWaitTime(long remainTime) {
return Math.max(remainTime / locks.size(), 1);
}
@Override
public void unlock() {
unlockInner(locks);
}
}
從上述源碼可以看出,Redisson 中的 RedLock 是基于 RedissonMultiLock(聯(lián)鎖)實(shí)現(xiàn)的,當(dāng) RedLock 是對(duì)集群的每個(gè)節(jié)點(diǎn)進(jìn)行加鎖,如果大多數(shù)節(jié)點(diǎn),也就是 N/2+1 個(gè)節(jié)點(diǎn)加鎖成功,則認(rèn)為 RedLock 加鎖成功。
5.存在問題
RedLock 主要存在以下兩個(gè)問題:
性能問題:RedLock 要等待大多數(shù)節(jié)點(diǎn)返回之后,才能加鎖成功,而這個(gè)過程中可能會(huì)因?yàn)榫W(wǎng)絡(luò)問題,或節(jié)點(diǎn)超時(shí)的問題,影響加鎖的性能。
并發(fā)安全性問題:當(dāng)客戶端加鎖時(shí),如果遇到 GC 可能會(huì)導(dǎo)致加鎖失效,但 GC 后誤認(rèn)為加鎖成功的安全事故,例如以下流程:
客戶端 A 請(qǐng)求 3 個(gè)節(jié)點(diǎn)進(jìn)行加鎖。
在節(jié)點(diǎn)回復(fù)處理之前,客戶端 A 進(jìn)入 GC 階段(存在 STW,全局停頓)。
之后因?yàn)榧渔i時(shí)間的原因,鎖已經(jīng)失效了。
客戶端 B 請(qǐng)求加鎖(和客戶端 A 是同一把鎖),加鎖成功。
客戶端 A GC 完成,繼續(xù)處理前面節(jié)點(diǎn)的消息,誤以為加鎖成功。
此時(shí)客戶端 B 和客戶端 A 同時(shí)加鎖成功,出現(xiàn)并發(fā)安全性問題。
6.已廢棄的 RedLock
因?yàn)?RedLock 存在的問題爭議較大,且沒有完美的解決方案,所以 Redisson 中已經(jīng)廢棄了 RedLock,這一點(diǎn)在 Redisson 官方文檔中能找到,如下圖所示:


課后思考
既然 RedLock 已經(jīng)被廢棄,那么想要實(shí)現(xiàn)分布式鎖,同時(shí)又想避免 Redis 單點(diǎn)故障問題,應(yīng)該使用哪種解決方案呢?
到此這篇關(guān)于淺析Redis中紅鎖RedLock的實(shí)現(xiàn)原理的文章就介紹到這了,更多相關(guān)Redis紅鎖RedLock內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于redis實(shí)現(xiàn)定時(shí)任務(wù)的方法詳解
這篇文章主要給大家介紹了基于redis實(shí)現(xiàn)定時(shí)任務(wù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
Redis 實(shí)現(xiàn)消息隊(duì)列實(shí)際案例
文章探討Redis作為消息隊(duì)列的三大核心方案(List、Pub/Sub、Stream)及適用場景,分析了輕量部署、高性能、多語言支持等優(yōu)勢,指出Stream在可靠性、消息確認(rèn)、死信隊(duì)列等企業(yè)級(jí)需求上表現(xiàn)最佳,適合電商等高吞吐場景,并提供了實(shí)際應(yīng)用案例與優(yōu)化建議,感興趣的朋友一起看看吧2025-09-09
Redis擊穿穿透雪崩產(chǎn)生原因分析及解決思路面試
這篇文章主要為大家介紹了Redis擊穿穿透雪崩產(chǎn)生原因及解決思路的面試問題答案參考,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進(jìn)步2022-03-03
阿里云服務(wù)器安裝配置redis的方法并且加入到開機(jī)啟動(dòng)(推薦)
這篇文章主要介紹了阿里云服務(wù)器安裝配置redis并且加入到開機(jī)啟動(dòng),需要的朋友可以參考下2017-12-12
如何使用注解方式實(shí)現(xiàn)?Redis?分布式鎖
這篇文章主要介紹了如何使用注解方式實(shí)現(xiàn)Redis分布式鎖,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,教大家如何優(yōu)雅的使用Redis分布式鎖,感興趣的小伙伴可以參考一下2022-07-07

