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

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

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

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

zk實(shí)現(xiàn)分布式鎖完全是依靠zk節(jié)點(diǎn)類型當(dāng)中的臨時(shí)序號(hào)節(jié)點(diǎn)來實(shí)現(xiàn)的

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

1.1.什么是鎖

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

1.2.鎖的使用場(chǎng)景

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

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

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

1.3.什么是分布式鎖

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

1.4.分布式鎖的使用場(chǎng)景

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

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

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

2.1.zk中鎖的種類:

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

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

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

當(dāng)需要上鎖的時(shí)候,就進(jìn)行創(chuàng)建臨時(shí)序號(hào)節(jié)點(diǎn),釋放鎖的時(shí)候就刪除節(jié)點(diǎn)。

2.2.zk如何上讀鎖

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

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

在這里插入圖片描述

2.3.zk如何上寫鎖

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

在這里插入圖片描述

2.4.?群效應(yīng)

如果?上述的上鎖?式,只要有節(jié)點(diǎn)發(fā)?變化,就會(huì)觸發(fā)其他節(jié)點(diǎn)的監(jiān)聽事件,這樣的話對(duì)zk的壓??常?,——?群效應(yīng)??梢哉{(diào)整成鏈?zhǔn)奖O(jiān)聽。解決這個(gè)問題。

在這里插入圖片描述

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

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

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

三、springboot整合分布式鎖

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

我直接是基于上一篇文章當(dāng)中的項(xiàng)目進(jìn)行 分布式鎖 練習(xí)的!

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

@Autowired
CuratorFramework curatorFramework;

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

    // 獲取鎖(假如一直沒拿到鎖這個(gè)方法一直會(huì)是阻塞的,就算不阻塞的情況下,這個(gè)方法耗時(shí)也是特別長(zhǎng),高達(dá)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);
    }
    // 釋放鎖(方法耗時(shí)13毫秒)
    interProcessLock.release();
    // 走到這一步的時(shí)候節(jié)點(diǎn)已經(jīng)被刪除了
    System.out.println("等待釋放鎖!");
}

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

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

這個(gè)是兩個(gè)獲取讀鎖的時(shí)候的節(jié)點(diǎn)場(chǎng)景:

在這里插入圖片描述

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

在這里插入圖片描述

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

這個(gè)肯定是不會(huì)的,因?yàn)榧偃缬锌蛻舳四玫搅随i,還沒釋放,服務(wù)掛了,這時(shí)候依據(jù)臨時(shí)節(jié)點(diǎn)的特性,當(dāng)臨時(shí)節(jié)點(diǎn)和客戶端斷開連接幾秒后會(huì)自動(dòng)刪除的,刪除節(jié)點(diǎn)也就意味著自動(dòng)釋放鎖!

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

到此這篇關(guān)于Spring Boot整合Zookeeper實(shí)現(xiàn)分布式鎖的文章就介紹到這了,更多相關(guān)Spring Boot整合Zookeeper分布式鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(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é)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    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攔截器實(shí)現(xiàn)數(shù)據(jù)權(quán)限詳解

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

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

    Java之SpringCloud Eurka注冊(cè)錯(cuò)誤解決方案

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

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

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

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

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

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

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

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

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

    Java線程等待用法實(shí)例分析

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

最新評(píng)論