分布式鎖實戰:Redis與Redisson的深度解析

一、分布式鎖的必要性

在分布式系統中,當多個節點需要對共享資源進行讀寫操作時,傳統的本地鎖(如Java的synchronized或ReentrantLock)無法跨節點生效。此時,必須引入分布式鎖來保證操作的原子性和一致性。分布式鎖需滿足以下核心特性:

  1. 互斥性:任意時刻僅一個客戶端持有鎖
  2. 防死鎖:即使持有鎖的客戶端崩潰,鎖仍可被釋放
  3. 可重入性:同一客戶端可多次獲取同一把鎖
  4. 一致性:解鎖操作必須由鎖的持有者執行

二、Redis分布式鎖實現

Redis實現分布式鎖主要利用Redis的setnx命令。
SETNX key value 是 Redis 的原子性命令,用于設置鍵值對,僅當鍵不存在時生效,否則不執行任何操作。

1. 基礎實現(SETNX+EXPIRE)

// 加鎖(非原子操作)
if (redisTemplate.execute((RedisCallback<Long>) connection -> connection.setNX(lockKey.getBytes(), UUID.randomUUID().toString().getBytes())) == 1) {redisTemplate.expire(lockKey, expireTime, TimeUnit.SECONDS);return true;
}
return false;
  • 問題:SETNX與EXPIRE的非原子性導致可能存在鎖未設置過期時間的風險

2. 原子化實現(SET命令增強)

// 原子化加鎖
Boolean success = redisTemplate.execute((RedisCallback<Boolean>) connection -> connection.set(lockKey.getBytes(), UUID.randomUUID().toString().getBytes(), Expiration.seconds(expireTime), RedisStringCommands.SetOption.SET_IF_ABSENT));
return success != null && success;
  • 優勢:通過SET命令的NX選項實現原子性加鎖與過期時間設置

3. 解鎖實現

// 解鎖(需驗證鎖歸屬)
if (UUID.fromString(redisTemplate.opsForValue().get(lockKey)).equals(currentUuid)) {redisTemplate.delete(lockKey);
}

三、Redis鎖的缺陷與優化

1. 鎖過期問題

  • 現象:業務執行時間超過鎖過期時間,導致鎖提前釋放
  • 解決方案
    • 動態調整過期時間
    • 使用Redisson的看門狗機制

2. 鎖誤刪風險

  • 現象:客戶端A的鎖過期后,客戶端B獲取鎖并被客戶端A誤刪
  • 解決方案
    // 使用Lua腳本保證原子性
    String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(lockKey), currentUuid);
    

四、Redisson分布式鎖進階

1. 加鎖過程

當一個線程嘗試獲取分布式鎖時,Redisson 會執行以下操作:

  • 原子操作:使用 Redis 的 SETNX(SET if Not eXists)命令來嘗試設置一個鍵值對,鍵表示鎖的名稱,值表示持有鎖的線程標識(通常是一個 UUID)。如果設置成功,說明該線程成功獲取到鎖;如果設置失敗,說明鎖已經被其他線程持有。
  • 設置過期時間:為了避免鎖被永久持有(例如持有鎖的線程崩潰),Redisson 會為鎖設置一個過期時間。可以使用 SET 命令的 NXEX 選項來原子性地完成設置鍵值對和過期時間的操作。
  • 鎖重入:Redisson 支持鎖重入,即同一個線程可以多次獲取同一把鎖而不會死鎖。為了實現鎖重入,Redisson 在 Redis 中存儲的鍵值對的值是一個計數器,每次線程獲取鎖時計數器加 1,釋放鎖時計數器減 1,當計數器為 0 時才真正釋放鎖。

2. 鎖續期機制

為了防止在業務邏輯執行期間鎖過期,Redisson 引入了鎖續期機制,也稱為“看門狗”機制:

  • 定時任務:當線程成功獲取鎖后,Redisson 會啟動一個定時任務,該任務會在鎖過期時間的三分之一處執行,嘗試對鎖進行續期。
  • Lua 腳本:續期操作使用 Lua 腳本來保證原子性,腳本會檢查鎖的持有者是否還是當前線程,如果是則更新鎖的過期時間。

3. 釋放鎖過程

當線程完成業務邏輯后,需要釋放鎖,Redisson 會執行以下操作:

  • 計數器減 1:如果是鎖重入的情況,先將計數器減 1。
  • 釋放鎖:當計數器為 0 時,使用 Lua 腳本來刪除 Redis 中的鍵值對,從而釋放鎖。Lua 腳本可以保證刪除操作的原子性,避免在刪除過程中出現并發問題。

示例代碼

以下是一個簡單的 Java 代碼示例,展示了如何使用 Redisson 獲取和釋放分布式鎖:

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;import java.util.concurrent.TimeUnit;public class RedissonLockExample {public static void main(String[] args) {// 創建 Redisson 客戶端Config config = new Config();config.useSingleServer().setAddress("redis://127.0.0.1:6379");RedissonClient redisson = Redisson.create(config);// 獲取鎖RLock lock = redisson.getLock("myLock");try {// 嘗試獲取鎖,等待 10 秒,鎖的過期時間為 30 秒boolean isLocked = lock.tryLock(10, 30, TimeUnit.SECONDS);if (isLocked) {// 模擬業務邏輯System.out.println("獲取到鎖,開始執行業務邏輯");Thread.sleep(5000);System.out.println("業務邏輯執行完畢");}} catch (InterruptedException e) {e.printStackTrace();} finally {// 釋放鎖if (lock.isHeldByCurrentThread()) {lock.unlock();System.out.println("鎖已釋放");}}// 關閉 Redisson 客戶端redisson.shutdown();}
}

4. 鎖模式對比

鎖類型特性適用場景
公平鎖按等待順序分配鎖高并發有序場景
聯鎖多個獨立Redis節點的組合鎖金融級安全場景
紅鎖多數節點達成共識的鎖機制分布式系統強一致性要求

五、最佳實踐建議

  1. 鎖粒度控制:避免粗粒度鎖,優先使用細粒度鎖
  2. 過期時間設置:根據業務耗時合理設置,建議30-60秒
  3. 異常處理:所有加鎖操作必須包含finally塊釋放鎖
  4. 監控報警:對鎖競爭、鎖超時等異常情況進行監控
  5. 降級策略:鎖獲取失敗時要有回退機制,避免系統雪崩

六、總結

Redis原生鎖與Redisson框架為分布式鎖提供了不同層級的解決方案:

  • Redis原生方案適用于輕量級場景,需關注原子性與鎖過期問題
  • Redisson框架通過自動續期、多種鎖模式等特性,提供了企業級的分布式鎖解決方案

在實際應用中,應根據系統規模、一致性要求和業務特性選擇合適的實現方式,同時結合監控和報警機制保障系統的穩定性。

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

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

相關文章

Dify本地安裝部署筆記

目錄 方式一【docker安裝】&#xff1a; 步驟 1&#xff1a;準備工作 步驟2: 克隆dify倉庫 步驟3:部署啟動dify 步驟 4&#xff1a;訪問 Dify 步驟5:升級dify 方式二【源碼安裝】&#xff1a; 步驟1. 硬件&#xff1a;最低安裝要求 步驟2: 業務服務前的3個服務 1. 安…

質檢LIMS系統在食品生產加工企業的應用 如何保證食品生產企業的安全

在食品生產加工領域&#xff0c;質量安全是貫穿全產業鏈的生命線。隨著《食品安全法》對全過程追溯要求的深化&#xff0c;傳統實驗室管理模式已難以滿足高效、精準的質量管控需求。質檢實驗室信息管理系統&#xff08;LIMS&#xff09;作為數字化升級的核心工具&#xff0c;正…

自動駕駛VLA模型技術解析與模型設計

1.前言 2025年被稱為“VLA上車元年”&#xff0c;以視覺語言動作模型&#xff08;Vision-Language-Action Model, VLA&#xff09;為核心的技術范式正在重塑智能駕駛行業。VLA不僅融合了視覺語言模型&#xff08;VLM&#xff09;的感知能力和端到端模型的決策能力&#xff0c;…

UDP套接字編程(代碼)

什么是socket套接字編程&#xff1f; 通過Ip地址 端口號這種方式定位一臺主機&#xff0c;這樣的方式我們就叫做socket套接字。 Udp Socket 接口介紹 這些案列我們使用的接口基本都是一樣的&#xff0c;所以在這里我先把接口介紹完&#xff0c;具體的細節后面在說明。 創…

汽車行業可信數據空間研究探索

近期&#xff0c;相關老師在新能源汽車國家大數據聯盟微課堂發表了題為“汽車行業可信數據空間研究探索”的演講&#xff0c;主要包括可信數據空間的概念內涵、汽車行業可信數據空間的發展現狀、數據流通場景和技術需求研究、汽車行業可信數據空間的場景建設建議四個方面展開。…

圓弧插補相關算法匯總(C++和ST源代碼)

運動控制需要了解相關的插補概念,在閱讀本篇博客之前需要了解相關的準備知識,常用鏈接如下: SMART PLC直線插補詳解-CSDN博客文章瀏覽閱讀2.1k次,點贊2次,收藏4次。本文介紹了SMART PLC中軸組對象的概念,詳細講解了直線插補的原理和指令使用,包括SMART PLC從V2.7版本開…

Entity Framework框架

深入理解C#中的Entity Framework框架&#xff1a;從理論到實踐 在C#開發中&#xff0c;與數據庫交互是幾乎所有應用程序的核心需求之一。Entity Framework (EF) 作為微軟官方推出的ORM框架&#xff0c;極大地簡化了數據庫操作。本文將帶您深入理解EF框架的核心概念&#xff0c…

C++11QT復習 (五)

文章目錄 **Day6-2 成員訪問運算符重載&#xff08;2025.03.25&#xff09;****1. 復習****2. 成員訪問運算符重載****2.1 箭頭運算符 (->) 重載****(1) 語法** **2.2 解引用運算符 (*) 重載****(1) 語法** **3. 代碼分析****3.1 代碼結構****3.2 代碼解析****(1) Data 類**…

簡歷含金量的描述和注意事項!

背景 最近&#xff0c;在公司負責后端相關面試&#xff0c;簡歷看了不下 50 份&#xff0c;面試 10&#xff0c;純手碼 2000 多字&#xff0c;說說我對簡歷的看法&#xff0c;希望給大家一點啟發。 教育經歷 在眾多求職面試中&#xff0c;我發現多數求職者容易忽視教育背景的…

cellnet框架概述

cellnet框架是一個?高性能、組件化、多協議支持?的開源服務器網絡庫&#xff0c;專注于游戲服務器、分布式的多進程通信等場景的開發。 一、核心特性 ?支持多個主流協議&#xff0c;包括TCP、UDP、HTTP、WebSocket。并且抽象底層協議差異&#xff0c;統一網絡連接管理?。 …

【加密社】如何創建自己的幣圈工具站

需要準備的工作 1.域名 2.服務器 周末的時候主要弄了快訊這方面的代碼 我這里用的是星球日報的api&#xff0c;也可以訂閱他們的rss&#xff0c;這部分在github上是開源的 https://github.com/ODAILY 我這里用的是WordPressonenav主題&#xff0c;然后用小工具在主頁展示&am…

Docker學習筆記(十一)宿主機無法鏈接宿主機問題處理

故障排查優先級排序 服務狀態 → 2. 端口監聽 → 3. 防火墻 → 4. 權限配置 → 5. 網絡路由 &#xff08;按此順序可覆蓋95%的常見問題?15&#xff09; mysql鏡像啟動命令&#xff1a; docker run -p 3306:3306 --restartalways --name mysqlv8 -e MYSQL_ROOT_PASSWORDCd…

力扣:回溯算法

組合I class Solution {List<List<Integer>> result new ArrayList(); // 所有結果集List<Integer> list new ArrayList(); // 當前結果集public List<List<Integer>> combine(int n, int k) {dfs(n, k, 1);return result;}public void dfs(i…

華為HCIE鴻蒙應用開發認證靠譜嗎?

在萬物互聯時代&#xff0c;智能終端設備的多樣性與協同需求催生了操作系統的革新。華為HarmonyOS&#xff08;鴻蒙系統&#xff09;憑借其分布式架構與全場景能力&#xff0c;正成為打破設備邊界、重塑用戶體驗的核心技術底座。HCIE鴻蒙應用開發認證作為華為認證體系的頂級資質…

23種設計模式-原型(Prototype)設計模式

原型設計模式 &#x1f6a9;什么是原型設計模式&#xff1f;&#x1f6a9;原型設計模式的特點&#x1f6a9;原型設計模式的結構&#x1f6a9;原型設計模式的優缺點&#x1f6a9;原型設計模式的Java實現&#x1f6a9;代碼總結&#x1f6a9;總結 &#x1f6a9;什么是原型設計模式…

Oracle-rman restore遭遇RMAN-03002與ORA-19563

文章目錄 在原DB上檢查是否有重復的文件名&#xff1a;查看rman恢復的日志修正重名部分重新執行rman恢復結論&#xff1a; 在 RMAN 恢復過程中&#xff0c;遇到RMAN-03002連同ORA-19563:錯誤。 操作是將 Oracle 10.0.5的數據庫備份從 RMAN備份恢復到另一臺測試主機的同一個目錄…

運維網絡排查工具介紹與使用

作為一名運維工程師&#xff0c;日常工作中最令人頭疼的莫過于各種網絡故障。在過去一年半的運維生涯中&#xff0c;我積累了豐富的網絡故障排查經驗&#xff0c;今天就來和大家分享一下如何運用抓包工具&#xff08;Wireshark、tcpdump&#xff09;和網絡排查工具&#xff08;…

解決vscode終端和本地終端python版本不一致的問題

&#x1f33f; 問題描述 本地終端&#xff1a; vscode終端&#xff1a; 別被這個給騙了&#xff0c;繼續往下看&#xff1a; 難怪我導入一些包的時候老提示找不到&#xff0c;在本地終端就不會這樣&#xff0c;于是我嚴重懷疑vscode中的python版本和終端不一樣&#xff0c…

Sublime全局搜索快捷鍵Ctrl+Shift+F不能使用解決

問題描述&#xff1a; 在安裝好Sublime后&#xff0c;我們使用快捷鍵進行全局搜索&#xff0c;發現沒有反應&#xff0c;但是中文輸入變成了繁體。 解決方案&#xff1a; 如截圖&#xff0c;在關閉簡繁切換的快捷鍵或者換成其他的就行

海康HTTP監聽報警事件數據

http監聽接收報警事件數據 海康獲取設備報警事件數據兩種方式&#xff1a; 1、sdk 布防監聽報警事件數據,服務端布防。&#xff08;前面文章有示例&#xff09; 2、http監聽接收報警事件數據&#xff0c;設備直接推送。 http監聽接收報警事件數據&#xff0c;服務端可以使用n…