zookeeper Curator(4):分布式鎖

文章目錄

  • 分布式鎖
  • 分布式鎖的實現
  • zookeeper 分布式鎖原理
  • Curator 實現分布式鎖API
      • 1. InterProcessMutex(分布式可重入互斥鎖)
      • 2. InterProcessSemaphoreMutex(分布式非可重入互斥鎖)
      • 3. InterProcessReadWriteLock(分布式讀寫鎖)
      • 4. InterProcessSemaphoreV2(分布式信號量)
      • 5. MultiSharedLock(多共享鎖)
      • 方案對比與推薦
  • 模擬12306售票案例
      • 案例背景
      • 實現步驟
        • 1. 依賴引入
        • 2. ZooKeeper 連接配置
        • 3. 票務服務(核心邏輯)
        • 4. 模擬并發搶票
      • 關鍵點解析
      • 運行結果示例
      • 擴展優化

分布式鎖

  • 在進行單機應用開發時,涉及女并發同步的時候,我們往往采用synchronized或者Lock的方式來解決多線程間的代碼同步問題,這時多線程的運行都在同一個JVM之下,沒有任何問題。
  • 但當我們的應用是分布式集群工作的情況下,屬于多個JVM下的工作環境,跨JVM之間已經無法通過多線程的鎖解決同步問題。
  • 那么就需要一種更高級的鎖機制來處理這種跨機器的進程之間的數據同步問題,這就是分布式鎖。

分布式鎖的實現

  • 基于緩存實現分布式鎖:redis,memcache
  • zookeeper實現分布式鎖:Curator
  • 數據庫層面實現分布式鎖: 樂觀鎖,悲觀鎖

zookeeper 分布式鎖原理

在這里插入圖片描述

  • 核心思想: 當客戶端要獲取鎖,則創建節點,使用完鎖,則刪除該節點。
  1. 客戶端時,在lock節點下創建 臨時順序 節點。
  2. 然后獲取lock下面的所有子節點,客戶端獲取到所有的子節點后,如果發現自己創建的子節點序號最小,那么就認為該客戶端獲取到了鎖。使用完鎖后,將該節點刪除。
    3 如果發現自己創建的節點并非lock所有節點中最小的,說明自己還沒有獲取到鎖,此時客戶端需要找到比自己小的那個節點,同時對其注冊事件監聽,監聽刪除事件。
    4 如果發現比自己小的那個節點被刪除,則客戶端的Watcher會收到相應通知,此時再次判斷自己創建的節點是否是lock子節點中最小的,如果是則獲取到了鎖,如果不是則重復以上步驟繼續獲取到比自己小的一個節點并注冊監聽。

Curator 實現分布式鎖API

Curator 提供了五種分布式鎖方案,每種方案適用于不同的業務場景,以下是具體介紹:

1. InterProcessMutex(分布式可重入互斥鎖)

  • 特點
    • 可重入:同一線程可多次獲取鎖,避免死鎖。
    • 互斥性:基于 ZooKeeper 臨時順序節點實現全局互斥,確保任何時刻只有一個客戶端持有鎖。
    • 自動釋放:通過臨時節點的特性,客戶端宕機時鎖自動釋放。
  • 適用場景
    • 需要線程安全的分布式資源訪問(如訂單處理、庫存扣減)。
  • 示例代碼
    CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", new ExponentialBackoffRetry(1000, 3));
    client.start();
    InterProcessMutex lock = new InterProcessMutex(client, "/locks/myLock");
    lock.acquire(); // 獲取鎖
    try {// 執行業務邏輯
    } finally {lock.release(); // 釋放鎖
    }
    

2. InterProcessSemaphoreMutex(分布式非可重入互斥鎖)

  • 特點
    • 非可重入:同一線程重復獲取鎖會阻塞,避免誤用導致的死鎖。
    • 輕量級:相比可重入鎖,實現更簡單,性能略高。
  • 適用場景
    • 需要嚴格互斥且無需重入的場景(如分布式任務調度)。
  • 示例代碼
    InterProcessSemaphoreMutex lock = new InterProcessSemaphoreMutex(client, "/locks/nonReentrantLock");
    lock.acquire(); // 獲取鎖
    try {// 執行業務邏輯
    } finally {lock.release(); // 釋放鎖
    }
    

3. InterProcessReadWriteLock(分布式讀寫鎖)

  • 特點
    • 讀寫分離:允許多個讀鎖并發,寫鎖獨占。
    • 公平性:基于 ZooKeeper 節點順序實現公平鎖,避免寫鎖饑餓。
  • 適用場景
    • 讀多寫少的場景(如分布式緩存更新、配置中心)。
  • 示例代碼
    InterProcessReadWriteLock rwLock = new InterProcessReadWriteLock(client, "/locks/rwLock");
    InterProcessMutex readLock = rwLock.readLock(); // 讀鎖
    InterProcessMutex writeLock = rwLock.writeLock(); // 寫鎖
    readLock.acquire(); // 獲取讀鎖
    try {// 執行讀操作
    } finally {readLock.release(); // 釋放讀鎖
    }
    

4. InterProcessSemaphoreV2(分布式信號量)

  • 特點
    • 資源限制:控制同時訪問資源的客戶端數量(如許可證數量)。
    • 動態調整:可通過 ZooKeeper 節點動態修改信號量值。
  • 適用場景
    • 限流控制(如 API 調用限流、連接池管理)。
  • 示例代碼
    InterProcessSemaphoreV2 semaphore = new InterProcessSemaphoreV2(client, "/locks/semaphore", 3); // 允許3個客戶端同時訪問
    Lease lease = semaphore.acquire(); // 獲取信號量
    try {// 執行業務邏輯
    } finally {semaphore.returnLease(lease); // 釋放信號量
    }
    

5. MultiSharedLock(多共享鎖)

  • 特點
    • 組合鎖:允許客戶端同時獲取多個鎖,實現跨資源的原子操作。
    • 避免死鎖:通過全局順序獲取鎖,防止死鎖。
  • 適用場景
    • 需要跨多個資源協調的場景(如分布式事務)。
  • 示例代碼
    List<String> lockPaths = Arrays.asList("/locks/resource1", "/locks/resource2");
    MultiSharedLock multiLock = new MultiSharedLock(client, lockPaths);
    multiLock.acquire(); // 獲取所有鎖
    try {// 執行跨資源操作
    } finally {multiLock.release(); // 釋放所有鎖
    }
    

方案對比與推薦

鎖類型可重入并發性適用場景
InterProcessMutex需要線程安全的資源訪問
InterProcessSemaphoreMutex嚴格互斥場景
InterProcessReadWriteLock讀是讀高/寫低讀多寫少場景
InterProcessSemaphoreV2高(有限制)限流控制
MultiSharedLock跨資源原子操作
  • 推薦選擇
    • 默認場景:優先使用 InterProcessMutex,兼顧安全性和靈活性。
    • 高性能讀場景:選擇 InterProcessReadWriteLock 的讀鎖。
    • 限流場景:使用 InterProcessSemaphoreV2 控制并發量。
    • 復雜協調場景MultiSharedLock 實現跨資源同步。

模擬12306售票案例

以下是使用 Curator 的 InterProcessMutex 模擬 12306 售票系統 的分布式鎖案例,解決高并發下超賣問題:


案例背景

12306 售票系統需要保證:

  • 同一車次余票的原子性操作:多個用戶同時購票時,不能出現超賣(如余票為 1 時,兩個用戶同時搶到票)。
  • 分布式環境下的線程安全:多個售票服務節點(如不同服務器)同時處理請求時,需通過分布式鎖協調。

實現步驟

1. 依賴引入
 <dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>4.0.0</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.0.0</version></dependency>
2. ZooKeeper 連接配置
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;public class ZkClient {private static final String ZK_ADDRESS = "localhost:2181";private static CuratorFramework client;static {client = CuratorFrameworkFactory.newClient(ZK_ADDRESS,new ExponentialBackoffRetry(1000, 3));client.start();}public static CuratorFramework getClient() {return client;}
}
3. 票務服務(核心邏輯)
import org.apache.curator.framework.recipes.locks.InterProcessMutex;public class TicketService {private final InterProcessMutex lock;private int remainingTickets; // 剩余票數(模擬數據庫)public TicketService(String lockPath, int initialTickets) {this.lock = new InterProcessMutex(ZkClient.getClient(), lockPath);this.remainingTickets = initialTickets;}// 購票方法public boolean buyTicket(String userId) {try {// 1. 獲取分布式鎖(阻塞式)if (lock.acquire(10, TimeUnit.SECONDS)) { // 超時時間10秒try {// 2. 檢查余票(雙重檢查,避免鎖內耗時)if (remainingTickets <= 0) {System.out.println("用戶 " + userId + " 購票失敗:票已售罄");return false;}// 3. 模擬業務邏輯(如扣減庫存、生成訂單)Thread.sleep(50); // 模擬網絡延遲或耗時操作// 4. 扣減票數remainingTickets--;System.out.println("用戶 " + userId + " 購票成功!剩余票數:" + remainingTickets);return true;} finally {// 5. 釋放鎖lock.release();}}} catch (Exception e) {e.printStackTrace();}return false;}
}
4. 模擬并發搶票
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;public class TicketSimulation {public static void main(String[] args) throws InterruptedException {// 初始化票務服務(鎖路徑為 /tickets/train123,初始票數10)TicketService ticketService = new TicketService("/tickets/train123", 10);// 模擬5個用戶并發搶票ExecutorService executor = Executors.newFixedThreadPool(2);for (int i = 1; i <= 5; i++) {final String userId = "User-" + i;executor.execute(() -> ticketService.buyTicket(userId));}executor.shutdown();executor.awaitTermination(1, TimeUnit.MINUTES);ZkClient.getClient().close();}
}

關鍵點解析

  1. 分布式鎖的作用

    • 確保同一時間只有一個線程能操作余票,避免超賣。
    • 使用 ZooKeeper 臨時順序節點實現,客戶端宕機時鎖自動釋放。
  2. 鎖的粒度

    • 鎖路徑 /tickets/train123 對應具體車次,不同車次互不影響。
  3. 超時控制

    • lock.acquire(10, TimeUnit.SECONDS) 防止死鎖(如客戶端崩潰未釋放鎖)。
  4. 雙重檢查

    • 獲取鎖后再次檢查余票,避免鎖內耗時導致其他線程重復扣減。
  5. 性能優化

    • 鎖的持有時間盡可能短(僅包裹關鍵代碼段)。

運行結果示例

用戶 User-1 購票成功!剩余票數:9
用戶 User-2 購票成功!剩余票數:8
...
用戶 User-3 購票成功!剩余票數:0
用戶 User-2 購票失敗:票已售罄
...

擴展優化

  1. 數據庫集成

    • 實際場景中,余票應存儲在數據庫,通過鎖保證分布式事務(如扣減庫存和生成訂單的原子性)。
  2. 鎖的公平性

    • Curator 的 InterProcessMutex 默認公平鎖,按請求順序獲取鎖。
  3. Redisson 替代方案

    • 如果使用 Redis,可用 Redisson 的 RLock 實現類似功能。
  4. 鎖重試策略

    • 可通過 RetryNTimesRetryUntilElapsed 自定義重試邏輯。

通過 InterProcessMutex,12306 售票系統能安全處理高并發請求,確保數據一致性。

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

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

相關文章

設置方法區內存的大小

方法區內存配置 方法區&#xff08;Method Area&#xff09;是JVM內存模型的一部分&#xff0c;用于存儲類信息、常量、靜態變量等數據。在HotSpot虛擬機中&#xff0c;方法區的具體實現為永久代&#xff08;PermGen&#xff09;或元空間&#xff08;Metaspace&#xff09;&am…

用Flink打造實時數倉:生產環境中的“坑”與“解藥”

目錄 一、實時數倉的“野心”與“現實” 二、數據采集與接入:別讓“源頭”卡脖子 2.1 問題1:Kafka數據亂序與延遲 2.2 問題2:MySQL CDC數據同步異常 三、數據處理與計算:別讓“算力”成瓶頸 3.1 問題3:多表Join性能低下 3.2 問題4:窗口計算觸發延遲 四、狀態管理與…

linux 下 Doris 單點部署

目錄 1. Doris 下載 2. 環境準備 2.1 Linux 操作系統版本需求 2.2 部署依賴 3. Doris 部署 3.1 修改系統配置 3.1.1 修改系統句柄數 3.1.2 關閉swap分區 3.1.3 修改最大內存映射區域數量 3.2 開放端口 3.3 fe 部署 3.4 be 部署 3.5 be添加到Doris集群 4 驗證 4.…

mysql 小版本升級實戰分享

環境說明 當前版本:5.6.51 升級目標版本 mysql 5.7.41 服務啟停通過systemd管理 升級準備&#xff1a; 環境檢查 首先查看當前MySQL的版本信息&#xff0c;執行命令mysql -V&#xff0c;如圖&#xff1a; 備份數據 備份所有數據庫&#xff1a; 當數據量不是特別大的時候…

Python Ai語音識別教程

語音識別是將人類語音轉換為文本的技術&#xff0c;在現代應用中非常有用。本教程將介紹如何使用Python實現基本的AI語音識別功能。 一、文字轉語音 #文字轉語音 #安裝第三方庫 pip install pyttsx3 #導包 &#xff1a; import pyttsx3import pyttsx3#創建語音引擎 a1 pytts…

Day11 制作窗口

文章目錄 1. 顯示窗口&#xff08;harib08d&#xff09;2. 消除閃爍1&#xff08;harib08g&#xff09;3. 消除閃爍2&#xff08;harib08h&#xff09; 本章的前三節做了如下修改&#xff1a; 解決了鼠標無法隱藏在屏幕右側和下側的問題。當鼠標隱藏在右側時會在屏幕最左側產生…

python+uniapp基于微信小程序蜀味道江湖餐飲管理系統nodejs+java

文章目錄 具體實現截圖本項目支持的技術路線源碼獲取詳細視頻演示&#xff1a;文章底部獲取博主聯系方式&#xff01;&#xff01;&#xff01;&#xff01;本系統開發思路進度安排及各階段主要任務java類核心代碼部分展示主要參考文獻&#xff1a;源碼獲取/詳細視頻演示 ##項目…

postgresql增量備份系列二 pg_probackup

已經很久沒有發文章了,主要是最近工作上的內容都不適合發文章公開。可能往后文章發表也不這么頻繁了,不過大家有問題我們可以交流。之前有寫過PG增量備份的其他工具使用方法,pg_probackup也是應用比較多的PG備份工具。 一. pg_probackup pg_probackup 是一個用于管理 Postg…

云手機主要是指什么?

云手機是指一種可以運行在云服務器中的手機&#xff0c;主要是將云計算技術運用于網絡終端服務&#xff0c;通過云服務器來實現云服務的手機&#xff0c;也是一款深度結合了網絡服務的手機&#xff0c;通過自帶的系統和網絡終端可以通過網絡實現眾多功能。 那么&#xff0c;下面…

CAU數據挖掘 支持向量機

SVM大致思想 線性分類問題 在一群點中用線性函數分類&#xff1a; 但也有線性不可分問題&#xff1a; 線性不可分問題&#xff1a; 最大間隔法 兩個平行超平面間隔距離最大 軟間隔 部分難以區分的點忽略 升維 通過升維將非線性變為線性 計算統計理論基礎 學習過…

探索理解 Spring AI Advisors:構建可擴展的 AI 應用

Spring AI Advisors API 提供了一種靈活且強大的方式來攔截、修改和增強 Spring 應用程序中的 AI 驅動交互。其核心思想類似于 Spring AOP&#xff08;面向切面編程&#xff09;中的“通知”&#xff08;Advice&#xff09;&#xff0c;允許開發者在不修改核心業務邏輯的情況下…

Linux SSH服務全面配置指南:從基礎到安全加固

Linux SSH服務全面配置指南&#xff1a;從基礎到安全加固 概述 作為網絡安全工程師&#xff0c;SSH&#xff08;Secure Shell&#xff09;服務的安全配置是我們日常工作中不可忽視的重要環節。本文將從基礎配置到高級安全加固&#xff0c;全面解析SSH服務的各項參數&#xff…

.NET測試工具Parasoft dotTEST內置安全標準,編碼合規更高效

在追求開發速度的時代&#xff0c;確保代碼安全并滿足嚴苛的行業合規標準如OWASP、CWE、PCI DSS、ISO 26262等已成為開發者的核心挑戰&#xff0c;但開發人員常因復雜的編碼標準和漏洞排查而效率低下。.NET測試工具Parasoft dotTEST內置安全標準&#xff0c;實現即插即用&#…

對象的finalization機制Test

Java語言提供了對象終止(finalization)機制來允許開發人員自定義對象被銷毀之前的處理邏輯。當垃圾回收器發現沒有引用指向一個對象時&#xff0c;通常接下來要做的就是垃圾回收&#xff0c;即清除該對象&#xff0c;而finalization機制使得在清除此對象之前&#xff0c;總會先…

AI初學者如何對大模型進行微調?——零基礎保姆級實戰指南

僅需8GB顯存&#xff0c;三步完成個人專屬大模型訓練 四步實戰&#xff1a;從環境配置到模型發布 步驟1&#xff1a;云端環境搭建&#xff08;10分鐘&#xff09; 推薦使用阿里魔塔ModelScope免費GPU資源&#xff1a; # 注冊后執行環境初始化 pip3 install --upgrade pip pi…

“單一職責”模式之裝飾器模式

目錄 “單一職責”模式裝飾器模式 Decorator引例動機 Motivation模式定義結構 Structure要點總結 “單一職責”模式 在軟件組件的設計中&#xff0c;如果責任劃分的不清晰&#xff0c;使用繼承得到的結果往往是隨著需求的變化&#xff0c;子類急劇膨脹&#xff0c;同時充斥著重…

idea, CreateProcess error=206, 文件名或擴展名太長

idea, CreateProcess error206, 文件名或擴展名太長 解決 “CreateProcess error206, 文件名或擴展名太長” 錯誤 CreateProcess error206 是 Windows 系統特有的錯誤&#xff0c;表示命令行參數超出了 Windows 的 32767 字符限制。這個問題在 Java 開發中尤其常見&#xff0c…

一鍵高效率圖片MD5修改工具PHP版

文章目錄 圖片MD5修改工具項目簡介功能特點技術原理系統需求安裝方法使用方法Web界面模式命令行模式文件結構常見問題注意事項開發者信息效果演示更多干貨??1.如果我的博客對你有幫助、如果你喜歡我的博客內容,請 “??點贊” “??評論” “??收藏” 一鍵三連哦!2.??…

跨主機用 Docker Compose 部署 PostgreSQL + PostGIS 主從

q下面是跨主機用 Docker Compose 部署 PostgreSQL PostGIS 主從復制的完整詳細步驟&#xff08;主庫 從庫&#xff09;&#xff0c;主從都用官方 PostGIS 鏡像 postgis/postgis:15-3.3&#xff0c;并注意網絡與持久化。復制即可。 &#x1f6a9; 跨主機 PostgreSQL PostGIS …

會議動態|千眼狼高速攝像機、DIC測量系統等科學儀器亮相第十五屆全國爆炸力學學術會議

第十五屆全國爆炸力學學術會議于6月28日在紹興盛大召開&#xff0c;會議匯聚來自全國爆炸力學與沖擊領域專家學者2000余人&#xff0c;聚焦“爆炸與沖擊動力學工程應用”、“材料動態力學行為與損傷斷裂“、“工程爆破與毀傷評估”、“含能材料與水中爆炸”、“結構動態響應與安…