欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring?Boot整合Zookeeper實現(xiàn)分布式鎖的場景分析

 更新時間:2022年06月27日 09:28:01   作者:怪?咖@  
這篇文章主要介紹了Spring?Boot整合Zookeeper實現(xiàn)分布式鎖,zk實現(xiàn)分布式鎖完全是依靠zk節(jié)點類型當中的臨時序號節(jié)點來實現(xiàn)的,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下

溫馨提示本篇文章要求掌握zk的數(shù)據(jù)結(jié)構(gòu),以及臨時序號節(jié)點!

zk實現(xiàn)分布式鎖完全是依靠zk節(jié)點類型當中的臨時序號節(jié)點來實現(xiàn)的

一、Java當中關(guān)于鎖的概念

1.1.什么是鎖

鎖是用來控制多個線程訪問共享資源的方式,一般來說,一個鎖能夠防止多個線程同時訪問共享資源。

1.2.鎖的使用場景

以減庫存為例,庫存這時候就剩1個,那么我們得保證只會有1個請求真正的完成減1操作,假如代碼邏輯是,先從庫里查庫存,通過if條件判斷,如果有就減,沒有就返回購買失敗。

這時候并發(fā)訪問減庫存接口,可能這時候我們代碼當中的if判斷已經(jīng)失效了,多個請求同時查到還有一個,并且已經(jīng)進入了if判斷,沒有加鎖的話,這時候事情就比較嚴重了,庫存一下子就成了負數(shù)。

對于這塊代碼我們不希望同時有人減庫存,這時候就需要加鎖來控制,加完鎖之后,就是將并發(fā)請求改成了串行,也就是不管并發(fā)了多少個請求,我通過加鎖,只讓1個請求進行減庫存,你們?nèi)帗屾i資源吧,誰先搶到了就是誰的。

1.3.什么是分布式鎖

分布式鎖是控制 微服務(wù)集群 之間同步訪問共享資源的一種方式。

1.4.分布式鎖的使用場景

使用分布式鎖前提:微服務(wù)一定是集群,這里的微服務(wù)不是指的zk,而是指的我們的業(yè)務(wù)模塊,在項目當中一般的,由于并發(fā)量較高,往往會將業(yè)務(wù)拆分為一個模塊一個模塊,例如訂單模塊,庫存模塊,拆模塊其中一個目的就是為了針對于模塊的并發(fā)性進行集群部署,比如訂單模塊用的比較多,我可以搭建多個訂單模塊,但是盡管他們的模塊是多個,圍繞的數(shù)據(jù)還是共通的(一個數(shù)據(jù)庫)。

集群情況下,我們在代碼加普通鎖已經(jīng)解決不了問題,假如現(xiàn)在有三個庫存微服務(wù),設(shè)置了負載均衡的方式訪問,普通鎖只能控制自己的服務(wù)減庫存不會出現(xiàn)負數(shù),但是他控制不了其他兩個服務(wù),數(shù)據(jù)是共通的,所以這時候只能使用分布式鎖,通過分布式鎖來控制三個服務(wù)當庫存只有一個商品的時候,只能有一個服務(wù)訪問的請求可以減庫存成功。

二、zk實現(xiàn)分布式鎖

2.1.zk中鎖的種類:

  • 讀鎖:創(chuàng)建?個臨時序號節(jié)點,節(jié)點的名稱會包含READ的字母,表示是讀鎖,?家都可以讀,要想上讀鎖的前提:之前的鎖沒有寫鎖
  • 寫鎖:創(chuàng)建?個臨時序號節(jié)點,節(jié)點的名稱會包含WRIT的字母,表示是寫鎖,只有得到寫鎖的才能寫。要想上寫鎖的前提是,之前沒有任何鎖

讀鎖和寫鎖完全是按照創(chuàng)建的臨時序號節(jié)點的名稱來區(qū)分的!

  • 序號節(jié)點創(chuàng)建出的節(jié)點,根據(jù)先后順序,會在節(jié)點之后帶上?個數(shù)值,越往后執(zhí)?數(shù)值越?,類似于mysql的主鍵自增
  • 臨時節(jié)點 :臨時節(jié)點是在會話結(jié)束后,?動被刪除的,通過這個特性,zk可以實現(xiàn)服務(wù)注冊與發(fā)現(xiàn)的效果。假如會話關(guān)掉后大概10s左右,創(chuàng)建的臨時節(jié)點就會消失。這個會話就是指的連接zk的客戶端。
  • 臨時序號節(jié)點:就是上面兩個的結(jié)合體

當需要上鎖的時候,就進行創(chuàng)建臨時序號節(jié)點,釋放鎖的時候就刪除節(jié)點。

2.2.zk如何上讀鎖

  • 創(chuàng)建一個臨時序號節(jié)點
  • 獲取當前zk中序號比自己小的所有節(jié)點
  • 判斷最小節(jié)點是否是讀鎖:
  • 如果不是讀鎖的話,則上鎖失敗,為最小節(jié)點設(shè)置監(jiān)聽。阻塞等待,zk的watch機制會當最小節(jié)點發(fā)生變化時通知當前節(jié)點,于是再執(zhí)行第二步的流程
  • 如果是讀鎖的話,則上鎖成功

想要上讀鎖,主要就是需要看比他小的節(jié)點當中是否有寫鎖。如果有寫鎖,就需要等他用完之后刪除節(jié)點,通過watch機制來通知他,寫鎖已經(jīng)釋放,然后他再進行第二步判斷。

在這里插入圖片描述

2.3.zk如何上寫鎖

  • 創(chuàng)建一個臨時序號節(jié)點
  • 獲取zk中所有的子節(jié)點
  • 判斷自己是否是最小的節(jié)點:
  • 如果是,則上寫鎖成功
  • 如果不是,說明前面還有鎖,則上鎖失敗,監(jiān)聽最小的節(jié)點,如果最小節(jié)點有變化,則回到第二步。

在這里插入圖片描述

2.4.?群效應(yīng)

如果?上述的上鎖?式,只要有節(jié)點發(fā)?變化,就會觸發(fā)其他節(jié)點的監(jiān)聽事件,這樣的話對zk的壓??常?,——?群效應(yīng)。可以調(diào)整成鏈式監(jiān)聽。解決這個問題。

在這里插入圖片描述

假如并發(fā)了100個請求都需要獲取寫鎖,這時候創(chuàng)建了100個節(jié)點來監(jiān)聽最小節(jié)點,當最小節(jié)點發(fā)生變化的時候,意味著他一下子要進行通知100個節(jié)點,zk瞬間會壓力非常大。

所以這時候可以采用鏈式監(jiān)聽,鏈式監(jiān)聽仍然是依靠的序號節(jié)點的特點。就好比mysql設(shè)置自增后,不管多少并發(fā)請求,他仍然能保證id的唯一性,zk的序號節(jié)點同樣也是。讓他們都不再監(jiān)聽最小節(jié)點,而是監(jiān)聽他的上一個節(jié)點。當上一個節(jié)點釋放鎖后,那當前節(jié)點就可以創(chuàng)建寫鎖了。

這里還會遇到一個問題,假如他的上一個節(jié)點意外刪除了,但是并不是等著拿到鎖后釋放鎖,而是單純的不想等了,所以刪除了節(jié)點,而上面還有很多節(jié)點加著鎖呢,所以我們不能單純的靠上一個節(jié)點刪除后當前節(jié)點就進行加鎖。我們加寫鎖要保證的是,他上面沒有任何節(jié)點加鎖。這時候讓他進行監(jiān)聽上上個節(jié)點即可。假如上上個節(jié)點仍然有問題了,那就監(jiān)聽上上上個節(jié)點。總之一點就是盡量避免不讓多個節(jié)點同時去監(jiān)聽一個節(jié)點。

三、springboot整合分布式鎖

springboot整合curator客戶端:http://www.dbjr.com.cn/article/181082.htm

我直接是基于上一篇文章當中的項目進行 分布式鎖 練習(xí)的!

根據(jù)上面提到的zk分布式鎖實現(xiàn)思路,我們其實并不用去自己寫,在curator客戶端已經(jīng)給我們提供了現(xiàn)成的方法,我們只需要簡單的調(diào)用客戶端提供的方法,就可以實現(xiàn)分布式鎖功能!

@Autowired
CuratorFramework curatorFramework;

/**
 * 獲取讀鎖的條件是前面沒有寫鎖
 * 當/lock1節(jié)點不存在的時候,我們不需要手動去創(chuàng)建,獲取鎖的時候會自動創(chuàng)建
 * 自動創(chuàng)建的是臨時節(jié)點,用完之后釋放鎖的時候會刪除掉的
 * 獲取到鎖之后會在/lock1節(jié)點下創(chuàng)建一個臨時序號節(jié)點
 * 然后沒有獲取到鎖的線程也會創(chuàng)建一個節(jié)點,這時候處于等待期間
 * 釋放鎖的時候,首先會刪除掉自己的序號節(jié)點,然后假如沒有人在排隊用鎖,這時候會把/lock1節(jié)點也刪除掉
 *
 * @throws Exception
 */
@Test
void testGetReadLock() throws Exception {
    // 讀寫鎖
    InterProcessReadWriteLock interProcessReadWriteLock = new
            InterProcessReadWriteLock(curatorFramework, "/lock1");
    // 獲取讀鎖對象(創(chuàng)建對象耗時也就18毫秒)
    InterProcessLock interProcessLock = interProcessReadWriteLock.readLock();
    System.out.println("等待獲取讀鎖對象!");

    // 獲取鎖(假如一直沒拿到鎖這個方法一直會是阻塞的,就算不阻塞的情況下,這個方法耗時也是特別長,高達17秒)
    interProcessLock.acquire();

    // 正常的我們代碼假如走到了這一步,說明已經(jīng)獲取到鎖了,這里寫相關(guān)的業(yè)務(wù)代碼即可,執(zhí)行完記住釋放鎖
    System.out.println("獲取到了鎖!");
    for (int i = 1; i <= 100; i++) {
        Thread.sleep(3000);
        System.out.println(i);
    }
    // 釋放鎖(方法耗時13毫秒)
    interProcessLock.release();
    // 走到這一步的時候節(jié)點已經(jīng)被刪除了
    System.out.println("等待釋放鎖!");
}

/**
 * 獲取寫鎖的條件是前面沒有任何的鎖
 *
 * @throws Exception
 */
@Test
void testGetWriteLock() throws Exception {
    // 讀寫鎖
    InterProcessReadWriteLock interProcessReadWriteLock = new
            InterProcessReadWriteLock(curatorFramework, "/lock1");
    // 獲取寫鎖對象
    InterProcessLock
            interProcessLock = interProcessReadWriteLock.writeLock();
    System.out.println("等待獲取寫鎖對象!");
    // 獲取鎖(假如一直沒拿到鎖這個方法一直會是阻塞的)
    interProcessLock.acquire();
    for (int i = 1; i <= 100; i++) {
        Thread.sleep(3000);
        System.out.println(i);
    }
    // 釋放鎖
    interProcessLock.release();
    System.out.println("等待釋放鎖!");
}

/**
 * 方便測試多個線程獲取讀鎖
 *
 * @throws Exception
 */
@Test
void testGetReadLock1() throws Exception {
    testGetReadLock();
}

這個是兩個獲取讀鎖的時候的節(jié)點場景:

在這里插入圖片描述

這個是一個獲取讀鎖,一個獲取寫鎖的場景,然后讀鎖節(jié)點是0004,所以是后創(chuàng)建的,他只有等待0003釋放寫鎖,才能獲取到讀鎖。

在這里插入圖片描述

zk分布式鎖會產(chǎn)生死鎖嗎?

這個肯定是不會的,因為假如有客戶端拿到了鎖,還沒釋放,服務(wù)掛了,這時候依據(jù)臨時節(jié)點的特性,當臨時節(jié)點和客戶端斷開連接幾秒后會自動刪除的,刪除節(jié)點也就意味著自動釋放鎖!

正常情況不建議使用zk作為分布式鎖,效率屬實太慢。

到此這篇關(guān)于Spring Boot整合Zookeeper實現(xiàn)分布式鎖的文章就介紹到這了,更多相關(guān)Spring Boot整合Zookeeper分布式鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java Web最近面試題匯總

    Java Web最近面試題匯總

    在本篇文章里小編給大家整理的是一篇關(guān)于Java Web最近面試題匯總內(nèi)容,需要的朋友們可以學(xué)習(xí)下。
    2020-02-02
  • 利用maven deploy上傳本地jar至私服的方法

    利用maven deploy上傳本地jar至私服的方法

    這篇文章主要介紹了利用maven deploy上傳本地jar至私服的方法,本文結(jié)合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2023-02-02
  • 從內(nèi)存地址解析Java的static關(guān)鍵字的作用

    從內(nèi)存地址解析Java的static關(guān)鍵字的作用

    這篇文章主要介紹了從內(nèi)存地址解析Java的static關(guān)鍵字的作用,包括靜態(tài)成員變量和靜態(tài)方法等重要內(nèi)容,需要的朋友可以參考下
    2015-10-10
  • Mybatis攔截器實現(xiàn)數(shù)據(jù)權(quán)限詳解

    Mybatis攔截器實現(xiàn)數(shù)據(jù)權(quán)限詳解

    這篇文章主要介紹了Mybatis攔截器實現(xiàn)數(shù)據(jù)權(quán)限詳解, 通過Mybatis攔截器我們可以攔截某些方法的調(diào)用,我們可以選擇在這些被攔截的方法執(zhí)行前后加上某些邏輯,需要的朋友可以參考下
    2023-11-11
  • Java之SpringCloud Eurka注冊錯誤解決方案

    Java之SpringCloud Eurka注冊錯誤解決方案

    這篇文章主要介紹了Java之SpringCloud Eurka注冊錯誤解決方案,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • IntelliJ IDEA設(shè)置代碼的快捷編輯模板Live Templates

    IntelliJ IDEA設(shè)置代碼的快捷編輯模板Live Templates

    今天小編就為大家分享一篇關(guān)于IntelliJ IDEA設(shè)置代碼的快捷編輯模板Live Templates,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-10-10
  • Java靜態(tài)泛型使用方法實例解析

    Java靜態(tài)泛型使用方法實例解析

    這篇文章主要介紹了Java靜態(tài)泛型使用方法實例解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-06-06
  • MyBatis游標Cursor的正確使用和百萬數(shù)據(jù)傳輸?shù)膬?nèi)存測試

    MyBatis游標Cursor的正確使用和百萬數(shù)據(jù)傳輸?shù)膬?nèi)存測試

    這篇文章主要介紹了MyBatis游標Cursor的正確使用和百萬數(shù)據(jù)傳輸?shù)膬?nèi)存測試,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • IDEA代碼規(guī)范插件P3C+代碼注釋模板配置方法

    IDEA代碼規(guī)范插件P3C+代碼注釋模板配置方法

    這篇文章主要介紹了IDEA代碼規(guī)范插件P3C+代碼注釋模板配置方法,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • Java線程等待用法實例分析

    Java線程等待用法實例分析

    這篇文章主要介紹了Java線程等待用法,結(jié)合實例形式分析了obj.wait()實現(xiàn)線程等待相關(guān)原理與操作技巧,需要的朋友可以參考下
    2018-09-09

最新評論