91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何理解分布式鎖的場景

發布時間:2021-10-14 11:39:46 來源:億速云 閱讀:138 作者:iii 欄目:web開發

本篇內容主要講解“如何理解分布式鎖的場景”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“如何理解分布式鎖的場景”吧!

秒殺場景案例

對于商品秒殺的場景,我們需要防止庫存超賣或者重復扣款等并發問題,我們通常需要使用分布式鎖,來解決共享資源競爭導致數據不一致的問題。

以手機秒殺的場景為例子,在搶購的過程中通常我們有三個步驟:

扣掉對應商品的庫存;2. 創建商品的訂單;3. 用戶支付。

對于這樣的場景我們就可以采用分布式鎖的來解決,比如我們在用戶進入秒殺 “下單“  鏈接的過程中,我們可以對商品庫存進行加鎖,然后完成扣庫存和其他操作,操作完成后。釋放鎖,讓下一個用戶繼續進入保證庫存的安全性;也可以減少因為秒殺失敗,導致 DB  回滾的次數。整個流程如下圖所示:

 如何理解分布式鎖的場景

注:對于鎖的粒度要根據具體的場景和需求來權衡。

三種分布式鎖

對于 Zookeeper 的分布式鎖實現,主要是利用 Zookeeper 的兩個特征來實現:

  1. 鴻蒙官方戰略合作共建——HarmonyOS技術社區

  2. Zookeeper 的一個節點不能被重復創建

  3. Zookeeper 的 Watcher 監聽機制

非公平鎖

對于非公平鎖,我們在加鎖的過程如下圖所示。

如何理解分布式鎖的場景

優點和缺點

其實上面的實現有優點也有缺點:

優點:

實現比較簡單,有通知機制,能提供較快的響應,有點類似 ReentrantLock 的思想,對于節點刪除失敗的場景由 Session  超時保證節點能夠刪除掉。

缺點:

重量級,同時在大量鎖的情況下會有 “驚群” 的問題。

“驚群” 就是在一個節點刪除的時候,大量對這個節點的刪除動作有訂閱 Watcher  的線程會進行回調,這對Zk集群是十分不利的。所以需要避免這種現象的發生。

解決“驚群”:

為了解決“驚群“問題,我們需要放棄訂閱一個節點的策略,那么怎么做呢?

  1. 鴻蒙官方戰略合作共建——HarmonyOS技術社區

  2. 我們將鎖抽象成目錄,多個線程在此目錄下創建瞬時的順序節點,因為 Zookeeper 會為我們保證節點的順序性,所以可以利用節點的順序進行鎖的判斷。

  3. 首先創建順序節點,然后獲取當前目錄下最小的節點,判斷最小節點是不是當前節點,如果是那么獲取鎖成功,如果不是那么獲取鎖失敗。

  4. 獲取鎖失敗的節點獲取當前節點上一個順序節點,對此節點注冊監聽,當節點刪除的時候通知當前節點。

  5. 當unlock的時候刪除節點之后會通知下一個節點。

公平鎖

基于非公平鎖的缺點,我們可以通過一下的方案來規避。

如何理解分布式鎖的場景

優點和缺點

優點: 如上借助于臨時順序節點,可以避免同時多個節點的并發競爭鎖,緩解了服務端壓力。

缺點: 對于讀寫場景來說,無法解決一致性的問題,如果讀的時候也去獲取鎖的話,這樣會導致性能下降,對于這樣的問題,我們可以通過讀寫鎖來實現如類似 jdk  中的 ReadWriteLock

讀寫鎖實現

對于讀寫鎖的特點:讀寫鎖在如果多個線程都是在讀的時候,是可以并發讀的,就是一個無鎖的狀態,如果有寫鎖正在操作的時候,那么讀鎖需要等待寫鎖。在加寫鎖的時候,由于前面的讀鎖都是并發,所以需要監聽最后一個讀鎖完成后執行寫鎖。步驟如下:

  1. 鴻蒙官方戰略合作共建——HarmonyOS技術社區

  2. read 請求, 如果前面是讀鎖,可以直接讀取,不需要監聽。如果前面是一個或者多個寫鎖那么只需要監聽最后一個寫鎖。

  3. write 請求,只需要對前面的節點監聽。Watcher 機制和互斥鎖一樣。

如何理解分布式鎖的場景

分布式鎖實戰

本文源碼中使用環境:JDK 1.8 、Zookeeper 3.6.x

Curator 組件實現

POM 依賴

<dependency>   <groupId>org.apache.curator</groupId>   <artifactId>curator-framework</artifactId>   <version>2.13.0</version> </dependency> <dependency>   <groupId>org.apache.curator</groupId>   <artifactId>curator-recipes</artifactId>   <version>2.13.0</version> </dependency>

互斥鎖運用

由于 Zookeeper 非公平鎖的 “驚群” 效應,非公平鎖在 Zookeeper 中其實并不是最好的選擇。下面是一個模擬秒殺的例子來使用  Zookeeper 分布式鎖。

public class MutexTest {     static ExecutorService executor = Executors.newFixedThreadPool(8);     static AtomicInteger stock = new AtomicInteger(3);     public static void main(String[] args) throws InterruptedException {         CuratorFramework client = getZkClient();         String key = "/lock/lockId_111/111";         final InterProcessMutex mutex = new InterProcessMutex(client, key);         for (int i = 0; i < 99; i++) {             executor.submit(() -> {                 if (stock.get() < 0) {                     System.err.println("庫存不足, 直接返回");                     return;                 }                 try {                     boolean acquire = mutex.acquire(200, TimeUnit.MILLISECONDS);                     if (acquire) {                         int s = stock.decrementAndGet();                         if (s < 0) {                             System.err.println("進入秒殺,庫存不足");                         } else {                             System.out.println("購買成功, 剩余庫存: " + s);                         }                     }                 } catch (Exception e) {                     e.printStackTrace();                 } finally {                     try {                         if (mutex.isAcquiredInThisProcess())                             mutex.release();                     } catch (Exception e) {                         e.printStackTrace();                     }                 }             });         }         while (true) {             if (executor.isTerminated()) {                 executor.shutdown();                 System.out.println("秒殺完畢剩余庫存為:" + stock.get());             }             TimeUnit.MILLISECONDS.sleep(100);         }     }     private static CuratorFramework getZkClient() {         String zkServerAddress = "127.0.0.1:2181";         ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3, 5000);         CuratorFramework zkClient = CuratorFrameworkFactory.builder()                 .connectString(zkServerAddress)                 .sessionTimeoutMs(5000)                 .connectionTimeoutMs(5000)                 .retryPolicy(retryPolicy)                 .build();         zkClient.start();         return zkClient;     } }

讀寫鎖運用

讀寫鎖可以用來保證緩存雙寫的強一致性的,因為讀寫鎖在多線程讀的時候是無鎖的, 只有在前面有寫鎖的時候才會等待寫鎖完成后訪問數據。

public class ReadWriteLockTest {     static ExecutorService executor = Executors.newFixedThreadPool(8);     static AtomicInteger stock = new AtomicInteger(3);     static InterProcessMutex readLock;     static InterProcessMutex writeLock;     public static void main(String[] args) throws InterruptedException {         CuratorFramework client = getZkClient();         String key = "/lock/lockId_111/1111";         InterProcessReadWriteLock readWriteLock = new InterProcessReadWriteLock(client, key);         readLock = readWriteLock.readLock();         writeLock = readWriteLock.writeLock();         for (int i = 0; i < 16; i++) {             executor.submit(() -> {                 try {                     boolean read = readLock.acquire(2000, TimeUnit.MILLISECONDS);                     if (read) {                         int num = stock.get();                         System.out.println("讀取庫存,當前庫存為: " + num);                         if (num < 0) {                             System.err.println("庫存不足, 直接返回");                             return;                         }                     }                 } catch (Exception e) {                     e.printStackTrace();                 }finally {                     if (readLock.isAcquiredInThisProcess()) {                         try {                             readLock.release();                         } catch (Exception e) {                             e.printStackTrace();                         }                     }                 }                 try {                     boolean acquire = writeLock.acquire(2000, TimeUnit.MILLISECONDS);                     if (acquire) {                         int s = stock.get();                         if (s <= 0) {                             System.err.println("進入秒殺,庫存不足");                         } else {                             s = stock.decrementAndGet();                             System.out.println("購買成功, 剩余庫存: " + s);                         }                     }                 } catch (Exception e) {                     e.printStackTrace();                 } finally {                     try {                         if (writeLock.isAcquiredInThisProcess())                             writeLock.release();                     } catch (Exception e) {                         e.printStackTrace();                     }                 }             });         }         while (true) {             if (executor.isTerminated()) {                 executor.shutdown();                 System.out.println("秒殺完畢剩余庫存為:" + stock.get());             }             TimeUnit.MILLISECONDS.sleep(100);         }     }     private static CuratorFramework getZkClient() {         String zkServerAddress = "127.0.0.1:2181";         ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3, 5000);         CuratorFramework zkClient = CuratorFrameworkFactory.builder()                 .connectString(zkServerAddress)                 .sessionTimeoutMs(5000)                 .connectionTimeoutMs(5000)                 .retryPolicy(retryPolicy)                 .build();         zkClient.start();         return zkClient;     } }

打印結果如下,一開始會有 8 個輸出結果為 讀取庫存,當前庫存為: 3 然后在寫鎖中回去順序的扣減少庫存。

讀取庫存,當前庫存為: 3 讀取庫存,當前庫存為: 3 讀取庫存,當前庫存為: 3 讀取庫存,當前庫存為: 3 讀取庫存,當前庫存為: 3 讀取庫存,當前庫存為: 3 讀取庫存,當前庫存為: 3 讀取庫存,當前庫存為: 3 購買成功, 剩余庫存: 2 購買成功, 剩余庫存: 1 購買成功, 剩余庫存: 0 進入秒殺,庫存不足 進入秒殺,庫存不足 進入秒殺,庫存不足 進入秒殺,庫存不足 進入秒殺,庫存不足 讀取庫存,當前庫存為: 0 讀取庫存,當前庫存為: 0 讀取庫存,當前庫存為: 0 讀取庫存,當前庫存為: 0 讀取庫存,當前庫存為: 0 讀取庫存,當前庫存為: 0 讀取庫存,當前庫存為: 0 讀取庫存,當前庫存為: 0 進入秒殺,庫存不足 進入秒殺,庫存不足 進入秒殺,庫存不足 進入秒殺,庫存不足 進入秒殺,庫存不足 進入秒殺,庫存不足 進入秒殺,庫存不足 進入秒殺,庫存不足

分布式鎖的選擇

咱們最常用的就是 Redis 的分布式鎖和 Zookeeper 的分布式鎖,在性能方面 Redis 的每秒鐘 TPS  可以上輕松上萬。在大規模的高并發場景我推薦使用 Redis 分布式鎖來作為推薦的技術方案。如果對并發要求不是特別高的場景可以使用 Zookeeper  分布式來處理。

到此,相信大家對“如何理解分布式鎖的場景”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

棋牌| 霞浦县| 阿城市| 江城| 秦皇岛市| 游戏| 马尔康县| 丰城市| 吉水县| 邳州市| 博客| 郑州市| 敦化市| 武定县| 无棣县| 连南| 汉川市| 泽普县| 辽阳县| 阳朔县| 板桥市| 嵊泗县| 德保县| 工布江达县| 舞钢市| 衡山县| 自贡市| 留坝县| 斗六市| 宾川县| 临高县| 安西县| 陆河县| 平度市| 闻喜县| 壶关县| 张掖市| 富阳市| 石嘴山市| 汶川县| 商都县|