分布式鎖實戰:Redisson vs. Redis 原生指令的性能對比

分布式鎖實戰:Redisson vs. Redis 原生指令的性能對比

引言

在DIY主題模板系統中,用戶可自定義聊天室的背景、圖標、動畫等元素。當多個運營人員或用戶同時修改同一模板時,若沒有鎖機制,可能出現“甲修改了背景色,乙覆蓋了甲的修改”的臟寫問題。此時,分布式鎖成為解決資源互斥訪問的核心工具。

市場上常見的分布式鎖方案有兩種:

  • Redis原生指令(如SET key value NX PX):輕量、性能高,但需手動處理超時、可重入等邊界問題;
  • Redisson:基于Redis的Java客戶端,封裝了RedLock算法,提供可重入鎖、公平鎖等高級特性,但實現復雜度更高。

本文將結合DIY主題模板系統的實際場景,從應用場景底層原理常見坑點壓測對比選型建議五大維度,深入解析兩種方案的差異,并給出實戰指導。

一、分布式鎖的應用場景:DIY主題模板系統的互斥需求

1.1 業務背景

DIY主題模板系統的核心功能是模板配置的增刪改查,典型操作流程如下:

  1. 運營人員通過后臺選擇模板ID(如template-123);
  2. 系統從數據庫讀取模板當前配置(背景色、圖標路徑等);
  3. 運營人員修改配置(如將背景色從#FFFFFF改為#FF0000);
  4. 系統將新配置寫回數據庫。

1.2 并發問題與鎖需求

當兩個運營人員同時修改同一模板時,可能出現以下問題:

  • 丟失更新:甲讀取舊配置→乙讀取舊配置→甲寫入新配置→乙寫入新配置(覆蓋甲的修改);
  • 臟數據:甲修改圖標路徑但未提交→乙基于舊路徑修改其他字段→甲回滾導致乙的數據依賴失效。

1.3 分布式鎖的價值

通過為模板ID(如template-123)加鎖,確保同一時刻僅一個請求能修改該模板,流程如圖1所示:

請添加圖片描述

二、Redisson的底層原理:基于RedLock算法的增強實現

2.1 為什么需要RedLock?

傳統的單節點Redis鎖(如SET key value NX PX)存在單點故障風險:若Redis主節點宕機且未同步到從節點,鎖可能被重復獲取。為解決此問題,Redis作者提出了RedLock算法(Redisson默認實現),通過多個獨立Redis實例(通常5個)提升可靠性。

2.2 RedLock的獲取與釋放流程

RedLock的核心邏輯是:向N個獨立Redis節點依次申請鎖,若在多數節點(N/2+1)成功獲取鎖,則認為加鎖成功。具體流程如圖2所示:
請添加圖片描述

2.3 Redisson的封裝與擴展

Redisson基于RedLock算法,提供了以下增強功能:

  • 可重入鎖:同一線程可多次獲取同一鎖(通過lockCount計數器實現);
  • 公平鎖:按請求順序分配鎖(通過Semaphore隊列實現);
  • 鎖續期:若業務執行時間超過鎖過期時間,自動延長鎖的有效期(“看門狗”機制);
  • 異步鎖:支持lockAsync()/unlockAsync()異步操作,避免阻塞線程。

三、原生Redis指令的坑:從“可用”到“可靠”的距離

3.1 原生Redis鎖的基礎實現

通過SET key value NX PX指令可實現基礎的分布式鎖(NX表示僅當key不存在時設置,PX設置過期時間):

public boolean tryLock(String lockKey, String requestId, int expireTime) {String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);return "OK".equals(result);
}public void unlock(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";jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
}

3.2 原生實現的三大致命問題

(1)問題一:超時導致的鎖誤刪

場景:業務執行時間超過鎖的過期時間(如鎖設置為30秒,業務執行了40秒),鎖自動釋放后,其他線程獲取鎖。此時原線程完成業務后,會刪除新線程的鎖,導致互斥失效。

原因:鎖的過期時間與業務執行時間不匹配,且原生實現未提供自動續期機制。

(2)問題二:不可重入導致的死鎖

場景:同一線程在未釋放鎖的情況下,再次嘗試獲取同一鎖(如遞歸調用),由于鎖已存在(NX條件不滿足),加鎖失敗,導致死鎖。

原因:原生Redis鎖僅記錄“鎖是否存在”,未記錄“持有鎖的線程ID”,無法判斷是否是同一線程重復獲取。

(3)問題三:單點故障導致的鎖失效

場景:Redis主節點宕機,未同步到從節點,新主節點未感知舊鎖存在,其他線程可重新獲取鎖,導致同一資源被多個線程同時修改。

原因:單節點Redis無法保證高可用,鎖的可靠性依賴單點。

四、壓測對比:Redisson vs. 原生Redis的性能差異

為量化兩種方案的性能差異,我們基于DIY主題模板系統的實際場景,設計了以下壓測實驗:

4.1 壓測環境與參數

維度配置/值
服務器8核16G Linux(CentOS 7)
Redis集群5節點(3主2從,主節點內存8G)
壓測工具JMeter(500線程,循環100次)
業務場景高并發修改同一模板(鎖競爭激烈)

4.2 壓測指標說明

  • TPS(每秒事務數):單位時間內成功獲取并釋放鎖的次數;
  • 平均延遲(ms):從請求加鎖到釋放鎖的總耗時;
  • 鎖沖突率(%):加鎖失敗的請求占比(原生Redis無自動重試,Redisson默認重試3次);
  • 鎖誤刪率(%):釋放非自己持有的鎖的概率。

4.3 壓測結果與分析

(1)場景1:短耗時業務(業務執行時間<鎖過期時間)
  • 原生Redis鎖

    • TPS:12000
    • 平均延遲:8ms
    • 鎖沖突率:5%(無重試)
    • 鎖誤刪率:0%(業務執行時間<過期時間,無超時)
  • Redisson(RedLock)

    • TPS:8000
    • 平均延遲:15ms
    • 鎖沖突率:2%(自動重試3次)
    • 鎖誤刪率:0%(看門狗自動續期)
(2)場景2:長耗時業務(業務執行時間>鎖過期時間)
  • 原生Redis鎖

    • TPS:11000
    • 平均延遲:9ms
    • 鎖沖突率:8%(部分請求因鎖過期被拒絕)
    • 鎖誤刪率:12%(原線程釋放已過期的鎖)
  • Redisson(RedLock)

    • TPS:7500
    • 平均延遲:18ms
    • 鎖沖突率:3%(自動重試+續期)
    • 鎖誤刪率:0%(看門狗續期至業務完成)
(3)場景3:Redis主節點宕機(模擬故障)
  • 原生Redis鎖

    • 鎖失效時間:30秒(主從切換耗時)
    • 鎖沖突率:40%(主節點宕機期間,從節點未同步鎖信息)
  • Redisson(RedLock)

    • 鎖失效時間:5秒(多數節點存活,仍可保證鎖有效)
    • 鎖沖突率:5%(僅需多數節點存活即可維持鎖)

4.4 數據結論

維度原生Redis鎖Redisson(RedLock)
性能(TPS)高(輕量無額外開銷)低(需與多個節點交互)
可靠性低(單點故障/超時誤刪)高(多節點+自動續期)
開發成本高(需手動處理邊界問題)低(封裝完善,開箱即用)

五、最佳實踐:如何選擇分布式鎖方案?

5.1 按業務場景選擇

(1)選擇原生Redis鎖的場景:
  • 性能敏感:如高頻交易系統(每秒上萬次鎖操作),輕量指令更適合;
  • 短耗時業務:業務執行時間明確<鎖過期時間(如5秒內),無需續期;
  • 弱一致性:允許偶發鎖沖突(如用戶評論點贊,重復點贊可通過冪等處理)。
(2)選擇Redisson的場景:
  • 強一致性:如財務系統、配置修改(必須保證互斥);
  • 長耗時業務:業務執行時間不確定(如文件上傳、復雜計算),需自動續期;
  • 高可用要求:系統依賴Redis集群(如電商大促、直播活動),需避免單點故障。

5.2 分布式鎖的通用設計原則

  1. 鎖粒度最小化:僅對核心資源加鎖(如模板ID),避免鎖整個服務;
  2. 過期時間合理:根據業務執行時間設置(建議為業務耗時的2~3倍),或啟用Redisson的看門狗續期;
  3. 唯一標識防誤刪:鎖值設置為請求唯一ID(如UUID),釋放時校驗(原生Redis通過Lua腳本實現);
  4. 監控與報警:記錄鎖獲取失敗率、鎖持有時間,及時發現異常(如鎖未釋放導致的死鎖)。

六、實戰:在DIY主題模板系統中落地

6.1 原生Redis鎖的實現(短耗時場景)

// 短耗時業務(如修改模板背景色,耗時約2秒)
public void updateTemplate(String templateId, String newConfig) {String lockKey = "lock:template:" + templateId;String requestId = UUID.randomUUID().toString();int expireTime = 5000; // 過期時間5秒(業務耗時2秒×2.5)// 加鎖boolean locked = tryLock(lockKey, requestId, expireTime);if (!locked) {throw new RuntimeException("模板正在被修改,請稍后再試");}try {// 業務邏輯:讀取舊配置→修改→寫入String oldConfig = templateDao.get(templateId);String mergedConfig = mergeConfig(oldConfig, newConfig);templateDao.update(templateId, mergedConfig);} finally {// 釋放鎖(通過Lua腳本防誤刪)unlock(lockKey, requestId);}
}

6.2 Redisson的實現(長耗時場景)

// 長耗時業務(如模板批量上傳,耗時約30秒)
public void batchUploadTemplate(String templateId, List<Resource> resources) {RLock lock = redissonClient.getLock("lock:template:" + templateId);try {// 加鎖(自動續期,過期時間默認30秒)boolean locked = lock.tryLock(10, TimeUnit.SECONDS); // 最多等待10秒if (!locked) {throw new RuntimeException("模板正在被修改,請稍后再試");}// 業務邏輯:上傳資源→生成配置→寫入數據庫(耗時30秒)for (Resource resource : resources) {ossClient.upload(resource.getPath(), resource.getContent());}String newConfig = generateConfig(resources);templateDao.update(templateId, newConfig);} finally {lock.unlock();}
}

總結

分布式鎖的選擇沒有“最優解”,需結合業務場景(性能要求、一致性等級)、技術成本(開發維護難度)、系統架構(Redis集群規模)綜合判斷:

  • 原生Redis鎖適合性能敏感、短耗時、弱一致性的場景,但需手動處理邊界問題;
  • Redisson適合強一致性、長耗時、高可用的場景,通過封裝降低開發成本。

在DIY主題模板系統中,我們對短耗時的“單個配置修改”使用原生Redis鎖(TPS高,滿足業務需求),對長耗時的“批量資源上傳”使用Redisson(避免鎖超時誤刪,保障數據一致性)。

希望本文的實踐經驗能幫助你在實際項目中做出更合理的選擇!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/86506.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/86506.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/86506.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++ 設計模式《復制粘貼的奇跡:小明的原型工廠》

&#x1f468;?&#x1f393; 模式名稱&#xff1a;原型模式&#xff08;Prototype Pattern&#xff09; &#x1f4d6; 背景故事 創業初期&#xff0c;小明每天加班寫配送路線、配送策略、營銷套餐。可當業務做大后&#xff0c;他發現大家常常下單“上次那個套餐”—— “老…

【Elasticsearch】映射:fielddata 詳解

映射&#xff1a;fielddata 詳解 1.fielddata 是什么2.fielddata 的工作原理3.主要用法3.1 啟用 fielddata&#xff08;通常在 text 字段上&#xff09;3.2 監控 fielddata 使用情況3.3 清除 fielddata 緩存 4.使用場景示例示例 1&#xff1a;對 text 字段進行聚合示例 2&#…

開源 vGPU 方案:HAMi,實現細粒度 GPU 切分

本文主要分享一個開源的 GPU 虛擬化方案&#xff1a;HAMi&#xff0c;包括如何安裝、配置以及使用。 相比于上一篇分享的 TimeSlicing 方案&#xff0c;HAMi 除了 GPU 共享之外還可以實現 GPU core、memory 得限制&#xff0c;保證共享同一 GPU 的各個 Pod 都能拿到足夠的資源。…

PlayDiffusion上線:AI語音編輯進入“無痕時代”

在語音合成與語音編輯領域&#xff0c;一個長期存在的挑戰是如何在修改語音內容的同時&#xff0c;保持原始語音的自然性、連貫性和說話人特征。近日&#xff0c;一款名為 PlayDiffusion 的新型 AI 語音修復模型應運而生&#xff0c;成功實現了這一目標。 PlayDiffusion 是一個…

2025年能源電力系統與流體力學國際會議 (EPSFD 2025)

2025年能源電力系統與流體力學國際會議&#xff08;EPSFD 2025&#xff09;將于本年度在美麗的杭州盛大召開。作為全球能源、電力系統以及流體力學領域的頂級盛會&#xff0c;EPSFD 2025旨在為來自世界各地的科學家、工程師和研究人員提供一個展示最新研究成果、分享實踐經驗及…

微信小程序前端面經

一、技術棧與編碼能力&#xff08;10min&#xff09; 1. Vue 3 & Composition API Q1&#xff1a;請解釋一下 ref 和 reactive 的區別&#xff1f;你在項目中是如何使用的&#xff1f; 答&#xff1a;ref是包裝一個原始值或對象&#xff0c;通過.value訪問&#xff0c;r…

rknn toolkit2搭建和推理

安裝Miniconda Miniconda - Anaconda Miniconda 選擇一個 新的 版本 &#xff0c;不用和RKNN的python版本保持一致 使用 ./xxx.sh進行安裝 下面配置一下載源 # 清華大學源&#xff08;最常用&#xff09; conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…

WordPress插件:AI多語言寫作與智能配圖、免費AI模型、SEO文章生成

厭倦手動寫WordPress文章&#xff1f;AI自動生成&#xff0c;效率提升10倍&#xff01; 支持多語言、自動配圖、定時發布&#xff0c;讓內容創作更輕松&#xff01; AI內容生成 → 不想每天寫文章&#xff1f;AI一鍵生成高質量內容&#xff01;多語言支持 → 跨境電商必備&am…

Houdini POP入門學習07 - 分組

使用PopGroup可對粒子進行分組操作&#xff0c;并通過表達式從而更靈活的處理粒子行為。 1.創建box作為發射器&#xff0c;連接popnet節點。 2.雙擊進入popnet&#xff0c;添加popwind添加向上風力。現在播放粒子可見粒子向上方移動。 3.添加popgroup進行分組&#xff0c;開啟…

機器學習復習3--模型評估

誤差與過擬合 我們將學習器對樣本的實際預測結果與樣本的真實值之間的差異稱為&#xff1a;誤差&#xff08;error&#xff09;。 誤差定義&#xff1a; ①在訓練集上的誤差稱為訓練誤差&#xff08;training error&#xff09;或經驗誤差&#xff08;empirical error&#x…

Docker 鏡像上傳到 AWS ECR:從構建到推送的全流程

一、在 EC2 實例中安裝 Docker&#xff08;適用于 Amazon Linux 2&#xff09; 步驟 1&#xff1a;連接到 EC2 實例 ssh -i your-key.pem ec2-useryour-ec2-public-ip步驟 2&#xff1a;安裝 Docker sudo yum update -y sudo amazon-linux-extras enable docker sudo yum in…

MobileNet 改進:基于MobileNetV2和SSPP的圖像分類

1.創新點分析 在計算機視覺領域,高效的圖像分類模型一直是研究熱點。 本文將詳細解析一個結合了MobileNetV2和空間金字塔池化(SSPP)的深度學習模型實現。 模型概述 這個代碼實現了一個輕量級但功能強大的圖像分類器,主要包含兩個核心組件: MobileNetV2作為特征提取器 自定…

Java中List的forEach用法詳解

在 Java 中&#xff0c;List.forEach() 是 Java 8 引入的一種簡潔的遍歷集合元素的方法。它基于函數式編程思想&#xff0c;接受一個 Consumer 函數式接口作為參數&#xff0c;用于對集合中的每個元素執行操作。 基本語法 java 復制 下載 list.forEach(consumer); 使用示…

涂鴉T5AI手搓語音、emoji、otto機器人從入門到實戰

“&#x1f916;手搓TuyaAI語音指令 &#x1f60d;秒變表情包大師&#xff0c;讓萌系Otto機器人&#x1f525;玩出智能新花樣&#xff01;開整&#xff01;” &#x1f916; Otto機器人 → 直接點明主體 手搓TuyaAI語音 → 強調 自主編程/自定義 語音控制&#xff08;TuyaAI…

計算機視覺與深度學習 | 基于MATLAB的相機標定

基于MATLAB的相機標定:原理、步驟與代碼實現 相機標定 基于MATLAB的相機標定:原理、步驟與代碼實現MATLAB相機標定完整流程1. 準備工作2. 采集標定圖像3. 導入圖像并檢測角點4. 生成世界坐標5. 執行相機標定6. 分析標定結果7. 應用標定結果校正圖像相機標定關鍵概念相機參數類…

物聯網專業核心課程以及就業方向

物聯網專業作為信息技術與產業應用深度融合的交叉學科&#xff0c;其課程體系覆蓋硬件、軟件、網絡、數據等全鏈條技術&#xff0c;就業方向則隨智能技術普及呈現多元化趨勢。以下是基于最新行業動態與教育實踐的系統分析&#xff1a; &#x1f4da; 一、物聯網專業核心課程體系…

mac 安裝homebrew (nvm 及git)

mac 安裝nvm 及git 萬惡之源 mac 安裝這些東西離不開Xcode。及homebrew 一、先說安裝git步驟 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安裝 Git&#xff08;推薦&#xff09; 步驟如下&#xff1a;打開終端&#xff08;Terminal.app&#xff09; 1.安裝 Homebrew…

vue3 定時器-定義全局方法 vue+ts

1.創建ts文件 路徑&#xff1a;src/utils/timer.ts 完整代碼&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 創建定時器con…

線性代數證明:把行列式的某一行(列)的k倍加到另一行(列),行列式的值不變

線性代數證明 把行列式的某一行&#xff08;列&#xff09;的k倍加到另一行&#xff08;列&#xff09;&#xff0c;行列式的值不變&#xff1a; 注意五角星的位置要用到另一條性質&#xff1a;若行列式的某一行&#xff08;列&#xff09;的元素都是兩數之和&#xff0c;則可以…

webrtc 在線測試, 如何在線拉流測試

1. 如下所示&#xff0c;使用騰訊提供的網頁即可&#xff0c;非常贊&#xff0c;測試直播拉流 webrtc協議 WebRTC Player Demo 2.截圖&#xff1a;