zookeeper系列(三)分布式鎖和服務(wù)優(yōu)化配置

前言:這幾天忙合作方的項(xiàng)目,就在剛剛?cè)缙谏暇€了, 才得以得空,閑下來,和大家吹吹牛,討論討論技術(shù),吹吹牛逼,打發(fā)著這閑淡的時(shí)光。話不多說 ?咋們直接進(jìn)入正題。討論一下ZK的分布式鎖以及在生產(chǎn)環(huán)境中如何優(yōu)化我們ZK的服務(wù)配置。

在分布式服務(wù)下,要想利用ZK實(shí)現(xiàn)一個(gè)分布式鎖,可利用zk的節(jié)點(diǎn)特殊性,來實(shí)現(xiàn)我們的分布式鎖。上一章 我們已經(jīng)介紹了ZK的節(jié)點(diǎn)基本知識(shí)。我們可以通過zk的臨時(shí)節(jié)點(diǎn)實(shí)現(xiàn)分布式鎖的機(jī)制

通過以下方式來實(shí)現(xiàn):

1 利用節(jié)點(diǎn)名稱的唯一性來實(shí)現(xiàn)共享鎖

ZooKeeper機(jī)制規(guī)定:同一個(gè)目錄下只能有一個(gè)唯一的文件名。例如:我們?cè)赯ookeeper目錄/test目錄下創(chuàng)建,兩個(gè)客戶端創(chuàng)建一個(gè)名為L(zhǎng)ock節(jié)點(diǎn),只有一個(gè)能夠成功。即只有一個(gè)服務(wù)能創(chuàng)建成功。即創(chuàng)建成功的服務(wù)獲取分布式鎖,解鎖時(shí) ,刪除相應(yīng)的節(jié)點(diǎn)即可,其余客戶端再次進(jìn)入競(jìng)爭(zhēng)創(chuàng)建節(jié)點(diǎn),直到所有的客戶端都能獲得鎖。完成自己的業(yè)務(wù)邏輯。

2 利用臨時(shí)順序節(jié)點(diǎn)實(shí)現(xiàn)共享鎖的一般做法

Zookeeper中有一種節(jié)點(diǎn)叫做順序節(jié)點(diǎn),故名思議,假如我們?cè)?lock/目錄下創(chuàng)建節(jié)3個(gè)點(diǎn),ZooKeeper集群會(huì)按照提起創(chuàng)建的順序來創(chuàng)建節(jié)點(diǎn),節(jié)點(diǎn)分別為/test/lock/0000000001、/test/lock/0000000002、/test/lock/0000000003。

ZK的臨時(shí)節(jié)點(diǎn)特性 ?當(dāng)客戶端與ZK集群斷開連接,則臨時(shí)節(jié)點(diǎn)自動(dòng)被刪除。

利用上面這兩個(gè)特性,我們來看下獲取實(shí)現(xiàn)分布式鎖的基本邏輯:

客戶端調(diào)用create()方法創(chuàng)建名為“test/lock-*”的節(jié)點(diǎn),需要注意的是,這里節(jié)點(diǎn)的創(chuàng)建類型需要設(shè)置為EPHEMERAL_SEQUENTIAL。

客戶端調(diào)用getChildren(“l(fā)ock-*”)方法來獲取所有已經(jīng)創(chuàng)建的子節(jié)點(diǎn),同時(shí)在這個(gè)節(jié)點(diǎn)上注冊(cè)上子節(jié)點(diǎn)變更通知的Watcher。

客戶端獲取到所有子節(jié)點(diǎn)path之后,循環(huán)子節(jié)點(diǎn) 發(fā)現(xiàn)創(chuàng)建的節(jié)點(diǎn)是所有節(jié)點(diǎn)中序號(hào)最小的,那么就認(rèn)為這個(gè)客戶端獲得了鎖。如果發(fā)現(xiàn)循環(huán)過程中發(fā)現(xiàn)自己創(chuàng)建的節(jié)點(diǎn)不是最小的,說明自己還沒有獲取到鎖,就開始等待,直到下次子節(jié)點(diǎn)變更通知的時(shí)候,再進(jìn)行子節(jié)點(diǎn)的獲取,判斷是否獲取鎖。

我知道的就這兩種方式,可能有其他的方式,網(wǎng)上有人說,還有其他的方式,具體的我沒有深入,也就不知道了,如果你深入了解的話,歡迎來信交流。

而在實(shí)際的項(xiàng)目中,我們通常會(huì)采取第一種方式,因?yàn)榈诙N方式有一個(gè)不好的地方:

即在獲取所有的子點(diǎn),判斷自己創(chuàng)建的節(jié)點(diǎn)是否已經(jīng)是序號(hào)最小的節(jié)點(diǎn)”,這個(gè)過程,在整個(gè)分布式鎖的競(jìng)爭(zhēng)過程中,大量重復(fù)運(yùn)行,并且絕大多數(shù)的運(yùn)行結(jié)果都是判斷出自己并非是序號(hào)最小的節(jié)點(diǎn),從而繼續(xù)等待下一次通知——這個(gè)顯然看起來不怎么科學(xué)。客戶端無端的接受到過多的和自己不相關(guān)的事件通知,這如果在集群規(guī)模大的時(shí)候,會(huì)對(duì)Server造成很大的性能影響,并且如果一旦同一時(shí)間有多個(gè)節(jié)點(diǎn)的客戶端斷開連接,這個(gè)時(shí)候,服務(wù)器就會(huì)像其余客戶端發(fā)送大量的事件通知 這是一個(gè)不友好的方式。所以我們一般利用ZK來實(shí)現(xiàn)我們分布式鎖的時(shí)候 通常會(huì)采用第一種方式來 實(shí)現(xiàn)。

像我們做游戲sdk 實(shí)時(shí)語(yǔ)音的,經(jīng)常對(duì)接游戲Cp 用戶量對(duì)于我們來說是很大,玩家通過我們的語(yǔ)音服務(wù)在游戲交流。那么場(chǎng)景來了:

? ? 不同的游戲方 對(duì)于我們來說 是不同的應(yīng)用 用戶登入我們實(shí)時(shí)語(yǔ)音時(shí) 我們是根據(jù)應(yīng)用隨機(jī)分配服務(wù)器的,那么在并發(fā)量大的時(shí)候 肯定在分配的時(shí)候 存在競(jìng)爭(zhēng),而我們的服務(wù) 又是分布式的 此時(shí)分布式鎖的場(chǎng)景就出現(xiàn)了。我們利用第一種方式來實(shí)現(xiàn)我們的分布式鎖和自己的業(yè)務(wù) 。

由于我們是用curator 來實(shí)現(xiàn)我們分布式鎖,而curator實(shí)現(xiàn)分布式鎖有好幾種鎖的方式:

1 共享鎖? InterProcessMutex

2 讀寫鎖? InterProcessReadWriteLock

3 共享信號(hào)量 InterProcessSemaphoreV2

大概就這么幾種吧? 而我們的實(shí)際的項(xiàng)目中用的是InterProcessMutex來實(shí)現(xiàn)分布式鎖

此鎖屬于可重入式鎖,當(dāng)一個(gè)客戶端獲取到lock鎖之后,可以重復(fù)調(diào)用acquire()而不會(huì)發(fā)生阻塞?;贗nterProcessSemaphoreMutex實(shí)現(xiàn)的分布式的分布式鎖是不可重入的,當(dāng)一個(gè)客戶端獲取到lock鎖之后,再次調(diào)用acquire方法獲取鎖時(shí)會(huì)發(fā)生阻塞?;贗nterProcessReadWriteLock實(shí)現(xiàn)的分布式鎖里邊包含了讀鎖與寫鎖,其中讀鎖與讀鎖互斥,讀鎖與寫鎖互斥,讀鎖與讀鎖不互斥。所以我們就選擇了InterProcessMutex 來實(shí)現(xiàn)吧。

在分配服務(wù)的時(shí)候 實(shí)現(xiàn)分布式鎖:


釋放鎖:

獲取鎖:

其他兩種鎖的實(shí)現(xiàn)方式如下:

InterProcessReadWriteLock簡(jiǎn)單的一個(gè)實(shí)例:

InterProcessSemaphoreV2 簡(jiǎn)單的一個(gè)實(shí)例:

關(guān)于ZK的分布式鎖大概就介紹到這里吧 我對(duì)ZK的分布式鎖也就了解的這么多了,如果你比我更深入的話 歡迎私信 我等渣渣向大神學(xué)習(xí)。

zk啟動(dòng)的時(shí)候 我們可以優(yōu)化我們的配置 比如以下幾種:
1 如果zk jvm內(nèi)存不夠的時(shí)候 我們要適當(dāng)?shù)脑黾樱?/p>

更改{ZK_HOME}/bin/zkServer.sh,大約在109-110行。

nohup $JAVA “-Dzookeeper.log.dir=${ZOO_LOG_DIR}” “-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}” \

-cp “$CLASSPATH” $JVMFLAGS $ZOOMAIN “$ZOOCFG” > “$_ZOO_DAEMON_OUT” 2>&1 < /dev/null &

改為:

nohup $JAVA “-Xmx1G -Xms1G -Dzookeeper.log.dir=${ZOO_LOG_DIR}”…

即可增加內(nèi)存。

2 zoo.cfg 配置文件 ?是zk的集群基本配置文件 ?調(diào)整里面的參數(shù)可以很好的保持我們的集群服務(wù)穩(wěn)定。所以大家要對(duì)里面的配置熟悉。如下:

1.tickTime:CS通信心跳數(shù)

Zookeeper 服務(wù)器之間或客戶端與服務(wù)器之間維持心跳的時(shí)間間隔,也就是每個(gè) tickTime 時(shí)間就會(huì)發(fā)送一個(gè)心跳。tickTime以毫秒為單位

tickTime=2000

2.initLimit:LF初始通信時(shí)限

集群中的follower服務(wù)器(F)與leader服務(wù)器(L)之間初始連接時(shí)能容忍的最多心跳數(shù)(tickTime的數(shù)量)

initLimit=10

3.syncLimit:LF同步通信時(shí)限

集群中的follower服務(wù)器與leader服務(wù)器之間請(qǐng)求和應(yīng)答之間能容忍的最多心跳數(shù)(tickTime的數(shù)量)。

syncLimit=5


4.dataDir:數(shù)據(jù)文件目錄

Zookeeper保存數(shù)據(jù)的目錄,默認(rèn)情況下,Zookeeper將寫數(shù)據(jù)的日志文件也保存在這個(gè)目錄里。

dataDir=E:\\comany\\zookeeper\\zkdata\\data1

5.dataLogDir:日志文件目錄

Zookeeper保存日志文件的目錄。

dataLogDir=E:\\comany\\zookeeper\\zkdata\\logs1


6.clientPort:客戶端連接端口

客戶端連接 Zookeeper 服務(wù)器的端口,Zookeeper 會(huì)監(jiān)聽這個(gè)端口,接受客戶端的訪問請(qǐng)求。

clientPort=2181

7.服務(wù)器名稱與地址:集群信息(服務(wù)器編號(hào),服務(wù)器地址,LF通信端口,選舉端口)

這個(gè)配置項(xiàng)的書寫格式比較特殊,規(guī)則如下:

server.1=127.0.0.1:2287:3387

#server.2=127.0.0.1:2288:3388

#server.3=127.0.0.1:2289:3389

尾記:今天就給大家介紹到這些了吧,我所知道的ZK的分布式鎖和服務(wù)優(yōu)化也就這些了,只怪自己太渣,沒辦法,只能講到這個(gè)程度,時(shí)間如白駒過隙,一晃之間就到了9月,一年也就快過完了,自己也越來越年長(zhǎng),自己還是一如既往的渣渣,危機(jī)感也越來越重,愿未來更要自我約束,自我鞭策,自我學(xué)習(xí)。

時(shí)間不早了 該回去了? 晚上在產(chǎn)業(yè)園吃了碗面 完全不管飽,身體要緊,回去補(bǔ)點(diǎn)狗糧,我是小志碼字,一個(gè)簡(jiǎn)單碼代碼的小人物。如果想了解這個(gè)項(xiàng)目和代碼? 加我微信? 微信號(hào):2B青年? 歡迎交流 相互學(xué)習(xí)。

補(bǔ)一張公司加班狗的圖照:


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容