天天看點

zookeeper

一、zookeeper常用場景總結

1.zookeeper是一個分布式協調服務;就是為使用者的分布式應用程式提供協調服務。zookeeper本身就是一個分布式程式,隻要有半數以上存活,zookeeper就能提供服務。

2.基本功能有兩個:管理(存儲、讀取)使用者程式送出的資料;并為使用者程式提供資料節點監聽服務。

3.Zookeeper所提供的服務涵蓋:主從協調、伺服器節點動态上下線、統一配置管理、分布式共享鎖、統一名稱服務……

4.常用場景

場景一:狀态感覺:(圖解:當一個接受資料的伺服器挂了,則被監聽,其他伺服器先頂替)

場景二:主從選舉

場景三:為soldcloud提供統一配置

二、zookeeper叢集節點角色配置設定原理

群首(leader),追随者(follower),觀察者(observer)。

        如何在zookeeper叢集中選舉出一個leader,zookeeper使用了三種算法,具體使用哪種算法,在配置檔案中是可以配置的,對應的配置項是”electionAlg”,其中1對應的是LeaderElection算法,2對應的是AuthFastLeaderElection算法,3對應的是FastLeaderElection算法.預設使用FastLeaderElection算法.

paxos算法的理論基礎.

1) 資料恢複階段

    首先,每個在zookeeper伺服器先讀取目前儲存在磁盤的資料,zookeeper中的每份資料,都有一個對應的id值,這個值是依次遞增的,換言之,越新的資料,對應的ID值就越大.

2) 向其他節點發送投票值

    在讀取資料完畢之後,每個zookeeper伺服器發送自己選舉的leader(首次選自己),這個協定中包含了以下幾部分的資料:

        a)所選舉leader的id(就是配置檔案中寫好的每個伺服器的id) ,在初始階段,每台伺服器的這個值都是自己伺服器的id,也就是它們都選舉自己為leader.

        b) 伺服器最大資料的id,這個值大的伺服器,說明存放了更新的資料.

        c)邏輯時鐘的值,這個值從0開始遞增,每次選舉對應一個值,也就是說:  如果在同一次選舉中,那麼這個值應該是一緻的 ;  邏輯時鐘值越大,說明這一次選舉leader的程序更新.

        d) 本機在目前選舉過程中的狀态,有以下幾種:LOOKING,FOLLOWING,OBSERVING,LEADING,顧名思義不必解釋了吧.

3)接受來自其他節點的資料

    每台伺服器将自己伺服器的以上資料發送到叢集中的其他伺服器之後,同樣的也需要接收來自其他伺服器的資料,它将做以下的處理:

(1)如果所接收資料中伺服器的狀态還是在選舉階段(LOOKING 狀态),那麼首先判斷邏輯時鐘值,又分為以下三種情況:

     a) 如果發送過來的邏輯時鐘大于目前的邏輯時鐘,那麼說明這是更新的一次選舉,此時需要更新一下本機的邏輯時鐘值,同時将之前收集到的來自其他伺服器的選舉清空,因為這些資料已經不再有效了.然後判斷是否需要更新目前自己的選舉情況.在這裡是根據選舉leader id,儲存的最大資料id來進行判斷的,這兩種資料之間對這個選舉結果的影響的權重關系是:首先看資料id,資料id大者勝出;其次再判斷leader id,leader id大者勝出.然後再将自身最新的選舉結果(也就是上面提到的三種資料)廣播給其他伺服器).

    b) 發送過來資料的邏輯時鐘小于本機的邏輯時鐘,說明對方在一個相對較早的選舉程序中,這裡隻需要将本機的資料發送過去就是了

    c) 兩邊的邏輯時鐘相同,此時也隻是調用totalOrderPredicate函數判斷是否需要更新本機的資料,如果更新了再将自己最新的選舉結果廣播出去就是了.

然後再處理兩種情況:

    1)伺服器判斷是不是已經收集到了所有伺服器的選舉狀态,如果是,那麼這台伺服器選舉的leader就定下來了,然後根據選舉結果設定自己的角色(FOLLOWING還是LEADER),然後退出選舉過程就是了.

    2)即使沒有收集到所有伺服器的選舉狀态,也可以根據該節點上選擇的最新的leader是不是得到了超過半數以上伺服器的支援,如果是,那麼目前線程将被阻塞等待一段時間(這個時間在finalizeWait定義)看看是不是還會收到目前leader的資料更優的leader,如果經過一段時間還沒有這個新的leader提出來,那麼這台伺服器最終的leader就确定了,否則進行下一次選舉. 

(2) 如果所接收伺服器不在選舉狀态,也就是在FOLLOWING或者LEADING狀态

做以下兩個判斷:

    a) 如果邏輯時鐘相同,将該資料儲存到recvset,如果所接收伺服器宣稱自己是leader,那麼将判斷是不是有半數以上的伺服器選舉它,如果是則設定選舉狀态退出選舉過程

    b) 否則這是一條與目前邏輯時鐘不符合的消息,那麼說明在另一個選舉過程中已經有了選舉結果,于是将該選舉結果加入到outofelection集合中,再根據outofelection來判斷是否可以結束選舉,如果可以也是儲存邏輯時鐘,設定選舉狀态,退出選舉過程.

代碼如下:

以一個簡單的例子來說明整個選舉的過程.

假設有五台伺服器組成的zookeeper叢集,它們的id從1-5,同時它們都是最新啟動的,也就是沒有曆史資料,在存放資料量這一點上,都是一樣的.假設這些伺服器依序啟動,來看看會發生什麼.

1) 伺服器1啟動,此時隻有它一台伺服器啟動了,它發出去的報沒有任何響應,是以它的選舉狀态一直是LOOKING狀态

2) 伺服器2啟動,它與最開始啟動的伺服器1進行通信,互相交換自己的選舉結果,由于兩者都沒有曆史資料,是以id值較大的伺服器2勝出,但是由于沒有達到超過半數以上的伺服器都同意選舉它(這個例子中的半數以上是3),是以伺服器1,2還是繼續保持LOOKING狀态.

3) 伺服器3啟動,根據前面的理論分析,伺服器3成為伺服器1,2,3中的老大,而與上面不同的是,此時有三台伺服器選舉了它,是以它成為了這次選舉的leader.

4) 伺服器4啟動,根據前面的分析,理論上伺服器4應該是伺服器1,2,3,4中最大的,但是由于前面已經有半數以上的伺服器選舉了伺服器3,是以它隻能接收當小弟的命了.

5) 伺服器5啟動,同4一樣,當小弟.

三、安裝zookeeper

    安裝到3台虛拟機上

    安裝好JDK

 上傳用工具。

    su – hadoop(切換到hadoop使用者)

    tar -zxvf zookeeper-3.4.5.tar.gz(解壓)

    mv zookeeper-3.4.5 zookeeper(重命名檔案夾zookeeper-3.4.5為zookeeper)

    1、su – root(切換使用者到root)

    2、vi /etc/profile(修改檔案)

    3、添加内容:

export ZOOKEEPER_HOME=/home/hadoop/zookeeper

export PATH=$PATH:$ZOOKEEPER_HOME/bin

    4、重新編譯檔案:

    source /etc/profile

    5、注意:3台zookeeper都需要修改

    6、修改完成後切換回hadoop使用者:

    su - hadoop

    1、用hadoop使用者操作

    cd zookeeper/conf

    cp zoo_sample.cfg zoo.cfg

    2、vi zoo.cfg

dataDir=/home/hadoop/zookeeper/data

dataLogDir=/home/hadoop/zookeeper/log

server.1=slave1:2888:3888 (主機名, 心跳端口、資料端口)

server.2=slave2:2888:3888

server.3=slave3:2888:3888

    4、建立檔案夾:

    cd /home/hadoop/zookeeper/

    mkdir -m 755 data

    mkdir -m 755 log

    5、在data檔案夾下建立myid檔案,myid的檔案内容為:

    cd data

    vi myid

    添加内容:

1

    scp -r /home/hadoop/zookeeper hadoop@slave2:/home/hadoop/

    scp -r /home/hadoop/zookeeper hadoop@slave3:/home/hadoop/

    到slave2上:修改myid為:2

    到slave3上:修改myid為:3

    zkServer.sh start

1、 jps(檢視程序)

2、 zkServer.sh status(檢視叢集狀态,主從資訊)

四、zookeeper結構和指令

    1、Zookeeper:一個leader,多個follower組成的叢集

    2、全局資料一緻:每個server儲存一份相同的資料副本,client無論連接配接到哪個server,資料都是一緻的

    3、分布式讀寫,更新請求轉發,由leader實施

    4、更新請求順序進行,來自同一個client的更新請求按其發送順序依次執行

    5、資料更新原子性,一次資料更新要麼成功,要麼失敗

    6、實時性,在一定時間範圍内,client能讀到最新資料

    1、階層化的目錄結構,命名符合正常檔案系統規範

    2、每個節點在zookeeper中叫做znode,并且其有一個唯一的路徑辨別

    3、節點Znode可以包含資料和子節點(但是EPHEMERAL類型的節點不能有子節點)

    4、用戶端應用可以在節點上設定螢幕

    任何一個節點内部都可以儲存資料。

    1、Znode有兩種類型:

        短暫(ephemeral)(斷開連接配接自己删除)

        持久(persistent)(斷開連接配接不删除)

    2、Znode有四種形式的目錄節點(預設是persistent )

        PERSISTENT

        PERSISTENT_SEQUENTIAL(持久序列/test0000000019 )

        EPHEMERAL

        EPHEMERAL_SEQUENTIAL

    3、建立znode時設定順序辨別,znode名稱後會附加一個值,順序号是一個單調遞增的計數器,由父節點維護,如建立的時候是aa,完成後是aa0000001

    4、在分布式系統中,順序号可以被用于為所有的事件進行全局排序,這樣用戶端可以通過順序号推斷事件的順序

    當一個用戶端修改了zookeeper叢集了解一個節點的資料之後,其他用戶端是可以感覺更新的通過查詢。但是當節點數量很小的時候,資料一緻性很快,但是當資料節點有幾十台,會有明顯的延遲

    當get path[watch],有一個監聽功能:當資料發生變化,在用戶端通過watch可以感覺到。當有了這個功能,用戶端程式,可以通過寫邏輯代碼進行監聽做出相應處理。

    注:擷取資料的時候,注冊監聽,隻能生效一次。還需注意監聽也有類型,包括階段資料變化(get path [watch])、節點類型變化(ls path [watch])。

五、zookeeper的JavaAPI使用

zookeeper用戶端内的守護線程及監聽機制

main線程建立zkclient對象 ,同時有connect和listener兩個線程;

connect線程發出getchildren請求,會一起發給zookeeper叢集以下資訊:IP,path,port

zookeeper叢集發現/path下的資料發生變化,根據IPport就會找見用戶端,進行socket通信,通路用戶端的listener線程

listener線程就會再調用zkclient對象的process方法

<code>public</code> <code>class</code> <code>SimpleZkClient {</code>

<code>    </code><code>private</code> <code>static</code> <code>final</code> <code>String connectString = </code><code>"mini1:2181,mini2:2181,mini3:2181"</code><code>;</code>

<code>    </code><code>private</code> <code>static</code> <code>final</code> <code>int</code> <code>sessionTimeout = </code><code>2000</code><code>;</code>

<code>    </code><code>ZooKeeper zkClient = </code><code>null</code><code>;</code>

<code>    </code><code>@Before</code>

<code>    </code><code>public</code> <code>void</code> <code>init() </code><code>throws</code> <code>Exception {</code>

<code>        </code><code>zkClient = </code><code>new</code> <code>ZooKeeper(connectString, sessionTimeout, </code><code>new</code> <code>Watcher() {</code>

<code>            </code><code>@Override</code>

<code>            </code><code>public</code> <code>void</code> <code>process(WatchedEvent event) {</code>

<code>                </code><code>// 收到事件通知後的回調函數(應該是我們自己的事件處理邏輯)</code>

<code>                </code><code>System.out.println(event.getType() + </code><code>"---"</code> <code>+ event.getPath());</code>

<code>                </code><code>try</code> <code>{</code>

<code>                    </code><code>zkClient.getChildren(</code><code>"/"</code><code>, </code><code>true</code><code>);</code>

<code>                </code><code>} </code><code>catch</code> <code>(Exception e) {</code>

<code>                </code><code>}</code>

<code>            </code><code>}</code>

<code>        </code><code>});</code>

<code>    </code><code>}</code>

<code>    </code><code>/**</code>

<code>     </code><code>* 資料的增删改查</code>

<code>     </code><code>* </code>

<code>     </code><code>* @throws InterruptedException</code>

<code>     </code><code>* @throws KeeperException</code>

<code>     </code><code>*/</code>

<code>    </code><code>// 建立資料節點到zk中</code>

<code>    </code><code>public</code> <code>void</code> <code>testCreate() </code><code>throws</code> <code>KeeperException, InterruptedException {</code>

<code>        </code><code>// 參數1:要建立的節點的路徑 參數2:節點大資料 參數3:節點的權限 參數4:節點的類型</code>

<code>        </code><code>String nodeCreated = zkClient.create(</code><code>"/eclipse"</code><code>, </code><code>"hellozk"</code><code>.getBytes(), Ids.OPEN_ACL_UNSAFE,</code>

<code>                </code><code>CreateMode.PERSISTENT);</code>

<code>        </code><code>// 上傳的資料可以是任何類型,但都要轉成byte[]</code>

<code>    </code><code>// 判斷znode是否存在</code>

<code>    </code><code>@Test</code>

<code>    </code><code>public</code> <code>void</code> <code>testExist() </code><code>throws</code> <code>Exception {</code>

<code>        </code><code>Stat stat = zkClient.exists(</code><code>"/eclipse"</code><code>, </code><code>false</code><code>);</code>

<code>        </code><code>System.out.println(stat == </code><code>null</code> <code>? </code><code>"not exist"</code> <code>: </code><code>"exist"</code><code>);</code>

<code>    </code><code>// 擷取子節點</code>

<code>    </code><code>public</code> <code>void</code> <code>getChildren() </code><code>throws</code> <code>Exception {</code>

<code>        </code><code>List&lt;String&gt; children = zkClient.getChildren(</code><code>"/"</code><code>, </code><code>true</code><code>);</code>

<code>        </code><code>for</code> <code>(String child : children) {</code>

<code>            </code><code>System.out.println(child);</code>

<code>        </code><code>}</code>

<code>        </code><code>Thread.sleep(Long.MAX_VALUE);</code>

<code>    </code><code>// 擷取znode的資料</code>

<code>    </code><code>public</code> <code>void</code> <code>getData() </code><code>throws</code> <code>Exception {</code>

<code>        </code><code>byte</code><code>[] data = zkClient.getData(</code><code>"/eclipse"</code><code>, </code><code>false</code><code>, </code><code>null</code><code>);</code>

<code>        </code><code>System.out.println(</code><code>new</code> <code>String(data));</code>

<code>    </code><code>// 删除znode</code>

<code>    </code><code>public</code> <code>void</code> <code>deleteZnode() </code><code>throws</code> <code>Exception {</code>

<code>        </code><code>// 參數2:指定要删除的版本,-1表示删除所有版本</code>

<code>        </code><code>zkClient.delete(</code><code>"/eclipse"</code><code>, -</code><code>1</code><code>);</code>

<code>    </code><code>public</code> <code>void</code> <code>setData() </code><code>throws</code> <code>Exception {</code>

<code>        </code><code>zkClient.setData(</code><code>"/app1"</code><code>, </code><code>"imissyou angelababy"</code><code>.getBytes(), -</code><code>1</code><code>);</code>

<code>        </code><code>byte</code><code>[] data = zkClient.getData(</code><code>"/app1"</code><code>, </code><code>false</code><code>, </code><code>null</code><code>);</code>

<code>}</code>

六、分布式應用系統伺服器上下線動态感覺

服務端啟動時去zookeeper叢集注冊資訊,建立臨時節點

用戶端啟動時就去getchildren,擷取到目前線上伺服器清單(并且注冊監聽)

當收到服務節點上下線事件通知的時候,就會再去執行process(重新再去擷取伺服器清單,再注冊監聽)

用戶端

<code>public</code> <code>class</code> <code>DistributedClient {</code>

<code>    </code><code>private</code> <code>static</code> <code>final</code> <code>String parentNode = </code><code>"/servers"</code><code>;</code>

<code>    </code><code>// 注意:加volatile的意義何在?</code>

<code>    </code><code>private</code> <code>volatile</code> <code>List&lt;String&gt; serverList;</code>

<code>    </code><code>private</code> <code>ZooKeeper zk = </code><code>null</code><code>;</code>

<code>     </code><code>* 建立到zk的用戶端連接配接</code>

<code>     </code><code>* @throws Exception</code>

<code>    </code><code>public</code> <code>void</code> <code>getConnect() </code><code>throws</code> <code>Exception {</code>

<code>        </code><code>zk = </code><code>new</code> <code>ZooKeeper(connectString, sessionTimeout, </code><code>new</code> <code>Watcher() {</code>

<code>                    </code><code>//重新更新伺服器清單,并且注冊了監聽</code>

<code>                    </code><code>getServerList();</code>

<code>     </code><code>* 擷取伺服器資訊清單</code>

<code>    </code><code>public</code> <code>void</code> <code>getServerList() </code><code>throws</code> <code>Exception {</code>

<code>        </code><code>// 擷取伺服器子節點資訊,并且對父節點進行監聽</code>

<code>        </code><code>List&lt;String&gt; children = zk.getChildren(parentNode, </code><code>true</code><code>);</code>

<code>        </code><code>// 先建立一個局部的list來存伺服器資訊</code>

<code>        </code><code>List&lt;String&gt; servers = </code><code>new</code> <code>ArrayList&lt;String&gt;();</code>

<code>            </code><code>// child隻是子節點的節點名</code>

<code>            </code><code>byte</code><code>[] data = zk.getData(parentNode + </code><code>"/"</code> <code>+ child, </code><code>false</code><code>, </code><code>null</code><code>);</code>

<code>            </code><code>servers.add(</code><code>new</code> <code>String(data));</code>

<code>        </code><code>// 把servers指派給成員變量serverList,已提供給各業務線程使用</code>

<code>        </code><code>serverList = servers;</code>

<code>        </code> 

<code>        </code><code>//列印伺服器清單</code>

<code>        </code><code>System.out.println(serverList);</code>

<code>     </code><code>* 業務功能</code>

<code>    </code><code>public</code> <code>void</code> <code>handleBussiness() </code><code>throws</code> <code>InterruptedException {</code>

<code>        </code><code>System.out.println(</code><code>"client start working....."</code><code>);</code>

<code>    </code> 

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>main(String[] args) </code><code>throws</code> <code>Exception {</code>

<code>        </code><code>// 擷取zk連接配接</code>

<code>        </code><code>DistributedClient client = </code><code>new</code> <code>DistributedClient();</code>

<code>        </code><code>client.getConnect();</code>

<code>        </code><code>// 擷取servers的子節點資訊(并監聽),從中擷取伺服器資訊清單</code>

<code>        </code><code>client.getServerList();</code>

<code>        </code><code>// 業務線程啟動</code>

<code>        </code><code>client.handleBussiness();</code>

伺服器端

<code>public</code> <code>class</code> <code>DistributedServer {</code>

<code>                    </code><code>zk.getChildren(</code><code>"/"</code><code>, </code><code>true</code><code>);</code>

<code>     </code><code>* 向zk叢集注冊伺服器資訊</code>

<code>     </code><code>* @param hostname</code>

<code>    </code><code>public</code> <code>void</code> <code>registerServer(String hostname) </code><code>throws</code> <code>Exception {</code>

<code>        </code><code>String create = zk.create(parentNode + </code><code>"/server"</code><code>, hostname.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);</code>

<code>        </code><code>System.out.println(hostname + </code><code>"is online.."</code> <code>+ create);</code>

<code>    </code><code>public</code> <code>void</code> <code>handleBussiness(String hostname) </code><code>throws</code> <code>InterruptedException {</code>

<code>        </code><code>System.out.println(hostname + </code><code>"start working....."</code><code>);</code>

<code>        </code><code>DistributedServer server = </code><code>new</code> <code>DistributedServer();</code>

<code>        </code><code>server.getConnect();</code>

<code>        </code><code>// 利用zk連接配接注冊伺服器資訊</code>

<code>        </code><code>server.registerServer(args[</code><code>0</code><code>]);</code>

<code>        </code><code>// 啟動業務功能</code>

<code>        </code><code>server.handleBussiness(args[</code><code>0</code><code>]);</code>

測試

<code>public</code> <code>class</code> <code>Test {</code>

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>main(String[] args) {</code>

<code>        </code><code>System.out.println(</code><code>"主線程開始了"</code><code>);</code>

<code>        </code><code>Thread thread = </code><code>new</code> <code>Thread(</code><code>new</code> <code>Runnable() {</code>

<code>            </code><code>public</code> <code>void</code> <code>run() {</code>

<code>                </code><code>System.out.println(</code><code>"線程開始了"</code><code>);</code>

<code>                </code><code>while</code><code>(</code><code>true</code><code>){</code>

<code>                    </code> 

<code>        </code><code>thread.setDaemon(</code><code>true</code><code>);</code>

<code>        </code><code>thread.start();</code>

補:DistributedClientLock

<code>public</code> <code>class</code> <code>DistributedClientLock {</code>

<code>    </code><code>// 會話逾時</code>

<code>    </code><code>private</code> <code>static</code> <code>final</code> <code>int</code> <code>SESSION_TIMEOUT = </code><code>2000</code><code>;</code>

<code>    </code><code>// zookeeper叢集位址</code>

<code>    </code><code>private</code> <code>String hosts = </code><code>"mini1:2181,mini2:2181,mini3:2181"</code><code>;</code>

<code>    </code><code>private</code> <code>String groupNode = </code><code>"locks"</code><code>;</code>

<code>    </code><code>private</code> <code>String subNode = </code><code>"sub"</code><code>;</code>

<code>    </code><code>private</code> <code>boolean</code> <code>haveLock = </code><code>false</code><code>;</code>

<code>    </code><code>private</code> <code>ZooKeeper zk;</code>

<code>    </code><code>// 記錄自己建立的子節點路徑</code>

<code>    </code><code>private</code> <code>volatile</code> <code>String thisPath;</code>

<code>     </code><code>* 連接配接zookeeper</code>

<code>    </code><code>public</code> <code>void</code> <code>connectZookeeper() </code><code>throws</code> <code>Exception {</code>

<code>        </code><code>zk = </code><code>new</code> <code>ZooKeeper(hosts, SESSION_TIMEOUT, </code><code>new</code> <code>Watcher() {</code>

<code>                    </code><code>// 判斷事件類型,此處隻處理子節點變化事件</code>

<code>                    </code><code>if</code> <code>(event.getType() == EventType.NodeChildrenChanged &amp;&amp; event.getPath().equals(</code><code>"/"</code> <code>+ groupNode)) {</code>

<code>                        </code><code>//擷取子節點,并對父節點進行監聽</code>

<code>                        </code><code>List&lt;String&gt; childrenNodes = zk.getChildren(</code><code>"/"</code> <code>+ groupNode, </code><code>true</code><code>);</code>

<code>                        </code><code>String thisNode = thisPath.substring((</code><code>"/"</code> <code>+ groupNode + </code><code>"/"</code><code>).length());</code>

<code>                        </code><code>// 去比較是否自己是最小id</code>

<code>                        </code><code>Collections.sort(childrenNodes);</code>

<code>                        </code><code>if</code> <code>(childrenNodes.indexOf(thisNode) == </code><code>0</code><code>) {</code>

<code>                            </code><code>//通路共享資源處理業務,并且在處理完成之後删除鎖</code>

<code>                            </code><code>doSomething();</code>

<code>                            </code> 

<code>                            </code><code>//重新注冊一把新的鎖</code>

<code>                            </code><code>thisPath = zk.create(</code><code>"/"</code> <code>+ groupNode + </code><code>"/"</code> <code>+ subNode, </code><code>null</code><code>, Ids.OPEN_ACL_UNSAFE,</code>

<code>                                    </code><code>CreateMode.EPHEMERAL_SEQUENTIAL);</code>

<code>                        </code><code>}</code>

<code>                    </code><code>}</code>

<code>                    </code><code>e.printStackTrace();</code>

<code>        </code><code>// 1、程式一進來就先注冊一把鎖到zk上</code>

<code>        </code><code>thisPath = zk.create(</code><code>"/"</code> <code>+ groupNode + </code><code>"/"</code> <code>+ subNode, </code><code>null</code><code>, Ids.OPEN_ACL_UNSAFE,</code>

<code>                </code><code>CreateMode.EPHEMERAL_SEQUENTIAL);</code>

<code>        </code><code>// wait一小會,便于觀察</code>

<code>        </code><code>Thread.sleep(</code><code>new</code> <code>Random().nextInt(</code><code>1000</code><code>));</code>

<code>        </code><code>// 從zk的鎖父目錄下,擷取所有子節點,并且注冊對父節點的監聽</code>

<code>        </code><code>List&lt;String&gt; childrenNodes = zk.getChildren(</code><code>"/"</code> <code>+ groupNode, </code><code>true</code><code>);</code>

<code>        </code><code>//如果争搶資源的程式就隻有自己,則可以直接去通路共享資源 </code>

<code>        </code><code>if</code> <code>(childrenNodes.size() == </code><code>1</code><code>) {</code>

<code>            </code><code>doSomething();</code>

<code>            </code><code>thisPath = zk.create(</code><code>"/"</code> <code>+ groupNode + </code><code>"/"</code> <code>+ subNode, </code><code>null</code><code>, Ids.OPEN_ACL_UNSAFE,</code>

<code>                    </code><code>CreateMode.EPHEMERAL_SEQUENTIAL);</code>

<code>     </code><code>* 處理業務邏輯,并且在最後釋放鎖</code>

<code>    </code><code>private</code> <code>void</code> <code>doSomething() </code><code>throws</code> <code>Exception {</code>

<code>        </code><code>try</code> <code>{</code>

<code>            </code><code>System.out.println(</code><code>"gain lock: "</code> <code>+ thisPath);</code>

<code>            </code><code>Thread.sleep(</code><code>2000</code><code>);</code>

<code>            </code><code>// do something</code>

<code>        </code><code>} </code><code>finally</code> <code>{</code>

<code>            </code><code>System.out.println(</code><code>"finished: "</code> <code>+ thisPath);</code>

<code>            </code><code>// 锟斤拷thisPath删锟斤拷, 锟斤拷锟斤拷thisPath锟斤拷client锟斤拷锟斤拷锟酵ㄖ�</code>

<code>            </code><code>// 锟潔當锟斤拷锟酵鳳拷锟斤拷</code>

<code>            </code><code>zk.delete(</code><code>this</code><code>.thisPath, -</code><code>1</code><code>);</code>

<code>        </code><code>DistributedClientLock dl = </code><code>new</code> <code>DistributedClientLock();</code>

<code>        </code><code>dl.connectZookeeper();</code>

本文轉自 叫我北北 51CTO部落格,原文連結:http://blog.51cto.com/qinbin/2049878

繼續閱讀