日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

分布式設(shè)計(jì)與開(kāi)發(fā)

 風(fēng)自向前 2010-08-30

分布式設(shè)計(jì)與開(kāi)發(fā)(一)------宏觀概述

分布式設(shè)計(jì)與開(kāi)發(fā)(二)------幾種必須了解的分布式算法

分布式設(shè)計(jì)與開(kāi)發(fā)(三)------高一致性服務(wù)ZooKeeper

分布式設(shè)計(jì)與開(kāi)發(fā)(四)------數(shù)據(jù)拆分

分布式設(shè)計(jì)與開(kāi)發(fā)(五)------數(shù)據(jù)庫(kù)高可用架構(gòu)

分布式設(shè)計(jì)與開(kāi)發(fā)(六)------讓memcached分布式

 
 
 
在IDF05(Intel Developer Forum 2005)上,Intel首席執(zhí)行官Craig Barrett就取消4GHz芯片計(jì)劃一事,半開(kāi)玩笑當(dāng)眾單膝下跪致歉,給廣大軟件開(kāi)發(fā)者一個(gè)明顯的信號(hào),單純依靠垂直提升硬件性能來(lái)提高系統(tǒng)性能的時(shí)代已結(jié)束,分布式開(kāi)發(fā)的時(shí)代實(shí)際上早已悄悄地成為了時(shí)代的主流,吵得很熱的云計(jì)算實(shí)際上只是包裝在分布式之外的商業(yè)概念,很多開(kāi)發(fā)者(包括我)都想加入研究云計(jì)算這個(gè)潮流,在google上通過(guò)“云計(jì)算”這個(gè)關(guān)鍵詞來(lái)查詢資料,查到的都是些概念性或商業(yè)性的宣傳資料,其實(shí)真正需要深入的還是那個(gè)早以被人熟知的概念------分布式。

分布式可繁也可以簡(jiǎn),最簡(jiǎn)單的分布式就是大家最常用的,在負(fù)載均衡服務(wù)器后加一堆web服務(wù)器,然后在上面搞一個(gè)緩存服務(wù)器來(lái)保存臨時(shí)狀態(tài),后面共享一個(gè)數(shù)據(jù)庫(kù),其實(shí)很多號(hào)稱分布式專(zhuān)家的人也就停留于此,大致結(jié)構(gòu)如下圖所示:

 

這種環(huán)境下真正進(jìn)行分布式的只是web server而已,并且web server之間沒(méi)有任何聯(lián)系,所以結(jié)構(gòu)和實(shí)現(xiàn)都非常簡(jiǎn)單。

有些情況下,對(duì)分布式的需求就沒(méi)這么簡(jiǎn)單,在每個(gè)環(huán)節(jié)上都有分布式的需求,比如Load Balance、DB、Cache和文件等等,并且當(dāng)分布式節(jié)點(diǎn)之間有關(guān)聯(lián)時(shí),還得考慮之間的通訊,另外,節(jié)點(diǎn)非常多的時(shí)候,得有監(jiān)控和管理來(lái)支撐。這樣看起來(lái),分布式是一個(gè)非常龐大的體系,只不過(guò)你可以根據(jù)具體需求進(jìn)行適當(dāng)?shù)夭眉?。按照最完備的分布式體系來(lái)看,可以由以下模塊組成:

 

分布式任務(wù)處理服務(wù):負(fù)責(zé)具體的業(yè)務(wù)邏輯處理

分布式節(jié)點(diǎn)注冊(cè)和查詢:負(fù)責(zé)管理所有分布式節(jié)點(diǎn)的命名和物理信息的注冊(cè)與查詢,是節(jié)點(diǎn)之間聯(lián)系的橋梁

分布式DB:分布式結(jié)構(gòu)化數(shù)據(jù)存取

分布式Cache:分布式緩存數(shù)據(jù)(非持久化)存取

分布式文件:分布式文件存取

網(wǎng)絡(luò)通信:節(jié)點(diǎn)之間的網(wǎng)絡(luò)數(shù)據(jù)通信

監(jiān)控管理:搜集、監(jiān)控和診斷所有節(jié)點(diǎn)運(yùn)行狀態(tài)

分布式編程語(yǔ)言:用于分布式環(huán)境下的專(zhuān)有編程語(yǔ)言,比如Elang、Scala

分布式算法:為解決分布式環(huán)境下一些特有問(wèn)題的算法,比如解決一致性問(wèn)題的Paxos算法

因此,若要深入研究云計(jì)算和分布式,就得深入研究以上領(lǐng)域,而這些領(lǐng)域每一塊的水都很深,都需要很底層的知識(shí)和技術(shù)來(lái)支撐,所以說(shuō),對(duì)于想提升技術(shù)的開(kāi)發(fā)者來(lái)說(shuō),以分布式來(lái)作為切入點(diǎn)是非常好的,可以以此為線索,探索計(jì)算機(jī)世界的各個(gè)角落。

分布式設(shè)計(jì)與開(kāi)發(fā)中有些疑難問(wèn)題必須借助一些算法才能解決,比如分布式環(huán)境一致性問(wèn)題,感覺(jué)以下分布式算法是必須了解的(隨著學(xué)習(xí)深入有待添加):

Paxos算法
一致性Hash算法
Paxos算法

1)問(wèn)題描述


分布式中有這么一個(gè)疑難問(wèn)題,客戶端向一個(gè)分布式集群的服務(wù)端發(fā)出一系列更新數(shù)據(jù)的消息,由于分布式集群中的各個(gè)服務(wù)端節(jié)點(diǎn)是互為同步數(shù)據(jù)的,所以運(yùn)行完客戶端這系列消息指令后各服務(wù)端節(jié)點(diǎn)的數(shù)據(jù)應(yīng)該是一致的,但由于網(wǎng)絡(luò)或其他原因,各個(gè)服務(wù)端節(jié)點(diǎn)接收到消息的序列可能不一致,最后導(dǎo)致各節(jié)點(diǎn)的數(shù)據(jù)不一致。舉一個(gè)實(shí)例來(lái)說(shuō)明這個(gè)問(wèn)題,下面是客戶端與服務(wù)端的結(jié)構(gòu)圖:

 

當(dāng)client1、client2、client3分別發(fā)出消息指令A(yù)、B、C時(shí),Server1~4由于網(wǎng)絡(luò)問(wèn)題,接收到的消息序列就可能各不相同,這樣就可能由于消息序列的不同導(dǎo)致Server1~4上的數(shù)據(jù)不一致。對(duì)于這么一個(gè)問(wèn)題,在分布式環(huán)境中很難通過(guò)像單機(jī)里處理同步問(wèn)題那么簡(jiǎn)單,而Paxos算法就是一種處理類(lèi)似于以上數(shù)據(jù)不一致問(wèn)題的方案。

2)算法本身

算法本身我就不進(jìn)行完整的描述和推導(dǎo),網(wǎng)上有大量的資料做了這個(gè)事情,但我學(xué)習(xí)以后感覺(jué)萊斯利·蘭伯特(Leslie Lamport,paxos算法的奠基人,此人現(xiàn)在在微軟研究院)的Paxos Made Simple 是學(xué)習(xí)paxos最好的文檔,它并沒(méi)有像大多數(shù)算法文檔那樣搞一堆公式和數(shù)學(xué)符號(hào)在那里嚇唬人,而是用人類(lèi)語(yǔ)言讓你搞清楚Paxos要解決什么問(wèn)題,是如何解決的。這里也借機(jī)抨擊一下那些學(xué)院派的研究者,要想讓別人認(rèn)可你的成果,首先要學(xué)會(huì)怎樣讓大多數(shù)人樂(lè)于閱讀你的成果,而這個(gè)描述Paxos算法的文檔就是我們學(xué)習(xí)的榜樣。

言歸正傳,透過(guò)Paxos算法的各個(gè)步驟和約束,其實(shí)它就是一個(gè)分布式的選舉算法,其目的就是要在一堆消息中通過(guò)選舉,使得消息的接收者或者執(zhí)行者能達(dá)成一致,按照一致的消息順序來(lái)執(zhí)行。其實(shí),以最簡(jiǎn)單的想法來(lái)看,為了達(dá)到大伙執(zhí)行相同序列的指令,完全可以通過(guò)串行來(lái)做,比如在分布式環(huán)境前加上一個(gè)FIFO隊(duì)列來(lái)接收所有指令,然后所有服務(wù)節(jié)點(diǎn)按照隊(duì)列里的順序來(lái)執(zhí)行。這個(gè)方法當(dāng)然可以解決一致性問(wèn)題,但它不符合分布式特性,如果這個(gè)隊(duì)列down掉或是不堪重負(fù)這么辦?而Paxos的高明之處就在于允許各個(gè)client互不影響地向服務(wù)端發(fā)指令,大伙按照選舉的方式達(dá)成一致,這種方式具有分布式特性,容錯(cuò)性更好。

說(shuō)到這個(gè)選舉算法本身,可以聯(lián)想一下現(xiàn)實(shí)社會(huì)中的選舉,一般說(shuō)來(lái)都是得票者最多者獲勝,而Paxos算法是序列號(hào)更高者獲勝,并且當(dāng)嘗試提交指令者被拒絕時(shí)(說(shuō)明它的指令所占有的序列號(hào)不是最高),它會(huì)重新以一個(gè)更好的序列參與再次選舉,通過(guò)各個(gè)提交者不斷參與選舉的方式,達(dá)到選出大伙公認(rèn)的一個(gè)序列的目的。也正是因?yàn)橛羞@個(gè)不斷參與選舉的過(guò)程,所以Paxos規(guī)定了三種角色(proposer,acceptor,和 learner)和兩個(gè)階段(accept和learn),三種角色的具體職責(zé)和兩個(gè)階段的具體過(guò)程就見(jiàn)Paxos Made Simple ,另外一個(gè)國(guó)內(nèi)的哥們寫(xiě)了個(gè)不錯(cuò)的PPT ,還通過(guò)動(dòng)畫(huà)描述了paxos運(yùn)行的過(guò)程。不過(guò)還是那句話不要一開(kāi)始就陷入算法的細(xì)節(jié)中,一定要多想想設(shè)計(jì)這些游戲規(guī)則的初衷是什么。

Paxos算法的最大優(yōu)點(diǎn)在于它的限制比較少,它允許各個(gè)角色在各個(gè)階段的失敗和重復(fù)執(zhí)行,這也是分布式環(huán)境下常有的事情,只要大伙按照規(guī)矩辦事即可,算法的本身保障了在錯(cuò)誤發(fā)生時(shí)仍然得到一致的結(jié)果。

3)算法的實(shí)現(xiàn)

Paxos的實(shí)現(xiàn)有很多版本,最有名的就是google chubby ,不過(guò)看不了源碼。開(kāi)源的實(shí)現(xiàn)可見(jiàn)libpaxos 。另外,ZooKeeper 也基于paxos解決數(shù)據(jù)一致性問(wèn)題,也可以看看它是如果實(shí)現(xiàn)paxos的。

4)適用場(chǎng)景

弄清楚paxos的來(lái)龍去脈后,會(huì)發(fā)現(xiàn)它的適用場(chǎng)景非常多,Tim有篇blog《Paxos在大型系統(tǒng)中常見(jiàn)的應(yīng)用場(chǎng)景》 專(zhuān)門(mén)談這個(gè)問(wèn)題。我所見(jiàn)到的項(xiàng)目里,naming service是運(yùn)用Paxos最廣的領(lǐng)域,具體應(yīng)用可參考ZooKeeper

一致性Hash算法

1)問(wèn)題描述

分布式常常用Hash算法來(lái)分布數(shù)據(jù),當(dāng)數(shù)據(jù)節(jié)點(diǎn)不變化時(shí)是非常好的,但當(dāng)數(shù)據(jù)節(jié)點(diǎn)有增加或減少時(shí),由于需要調(diào)整Hash算法里的模,導(dǎo)致所有數(shù)據(jù)得重新按照新的模分布到各個(gè)節(jié)點(diǎn)中去。如果數(shù)據(jù)量龐大,這樣的工作常常是很難完成的。一致性Hash算法是基于Hash算法的優(yōu)化,通過(guò)一些映射規(guī)則解決以上問(wèn)題

2)算法本身

對(duì)于一致性Hash算法本身我也不做完整的闡述,有篇blog《一致性hash算法 - consistent hashing》 描述這個(gè)算法非常到位,我就不重復(fù)造輪子了。

實(shí)際上,在其他設(shè)計(jì)和開(kāi)發(fā)領(lǐng)域我們也可以借鑒一致性Hash的思路,當(dāng)一個(gè)映射或規(guī)則導(dǎo)致有難以維護(hù)的問(wèn)題時(shí),可以考慮更一步抽象這些映射或規(guī)則,通過(guò)規(guī)則的變化使得最終數(shù)據(jù)的不變。一致性hash實(shí)際就是把以前點(diǎn)映射改為區(qū)段映射,使得數(shù)據(jù)節(jié)點(diǎn)變更后其他數(shù)據(jù)節(jié)點(diǎn)變動(dòng)盡可能小。這個(gè)思路在操作系統(tǒng)對(duì)于存儲(chǔ)問(wèn)題上體現(xiàn)很多,比如操作系統(tǒng)為了更優(yōu)化地利用存儲(chǔ)空間,區(qū)分了段、頁(yè)等不同緯度,加了很多映射規(guī)則,目的就是要通過(guò)靈活的規(guī)則避免物理變動(dòng)的代價(jià)

3)算法實(shí)現(xiàn)

一致性Hash算法本身比較簡(jiǎn)單,不過(guò)可以根據(jù)實(shí)際情況有很多改進(jìn)的版本,其目的無(wú)非是兩點(diǎn):

節(jié)點(diǎn)變動(dòng)后其他節(jié)點(diǎn)受影響盡可能小
節(jié)點(diǎn)變動(dòng)后數(shù)據(jù)重新分配盡可能均衡
實(shí)現(xiàn)這個(gè)算法就技術(shù)本身來(lái)說(shuō)沒(méi)多少難度和工作量,需要做的是建立起你所設(shè)計(jì)的映射關(guān)系,無(wú)需借助什么框架或工具,sourceforge上倒是有個(gè)項(xiàng)目libconhash ,可以參考一下

以上兩個(gè)算法在我看來(lái)就算從不涉及算法的開(kāi)發(fā)人員也需要了解的,算法其實(shí)就是一個(gè)策略,而在分布式環(huán)境常常需要我們?cè)O(shè)計(jì)一個(gè)策略來(lái)解決很多無(wú)法通過(guò)單純的技術(shù)搞定的難題,學(xué)習(xí)這些算法可以提供我們一些思路。

 

分布式環(huán)境中大多數(shù)服務(wù)是允許部分失敗,也允許數(shù)據(jù)不一致,但有些最基礎(chǔ)的服務(wù)是需要高可靠性,高一致性的,這些服務(wù)是其他分布式服務(wù)運(yùn)轉(zhuǎn)的基礎(chǔ),比如naming service、分布式lock等,這些分布式的基礎(chǔ)服務(wù)有以下要求:

高可用性
高一致性
高性能
對(duì)于這種有些挑戰(zhàn)CAP原則 的服務(wù)該如何設(shè)計(jì),是一個(gè)挑戰(zhàn),也是一個(gè)不錯(cuò)的研究課題,Apache的ZooKeeper也許給了我們一個(gè)不錯(cuò)的答案。ZooKeeper是一個(gè)分布式的,開(kāi)放源碼的分布式應(yīng)用程序協(xié)調(diào)服務(wù), 它暴露了一個(gè)簡(jiǎn)單的原語(yǔ)集,分布式應(yīng)用程序可以基于它實(shí)現(xiàn)同步服務(wù),配置維護(hù)和命名服務(wù)等。關(guān)于ZooKeeper更多信息可以參見(jiàn) 官方文檔

ZooKeeper的基本使用

搭一個(gè)分布式的ZooKeeper環(huán)境比較簡(jiǎn)單,基本步驟如下:

1)在各服務(wù)器安裝 ZooKeeper

下載ZooKeeper后在各服務(wù)器上進(jìn)行解壓即可

tar -xzf zookeeper-3.2.2.tar.gz

2)配置集群環(huán)境

分別各服務(wù)器的zookeeper安裝目錄下創(chuàng)建名為zoo.cfg的配置文件,內(nèi)容填寫(xiě)如下:

# The number of milliseconds of each tick  
tickTime=2000 
# The number of ticks that the initial  
# synchronization phase can take  
initLimit=10 
# The number of ticks that can pass between  
# sending a request and getting an acknowledgement  
syncLimit=5 
# the directory where the snapshot is stored.  
dataDir=/home/admin/zookeeper-3.2.2/data  
# the port at which the clients will connect  
clientPort=2181 
server.1=zoo1:2888:3888  
server.2=zoo2:2888:3888 
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
dataDir=/home/admin/zookeeper-3.2.2/data
# the port at which the clients will connect
clientPort=2181
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888 

其中zoo1和zoo2分別對(duì)應(yīng)集群中各服務(wù)器的機(jī)器名或ip,server.1和server.2中1和2分別對(duì)應(yīng)各服務(wù)器的zookeeper id,id的設(shè)置方法為在dataDir配置的目錄下創(chuàng)建名為myid的文件,并把id作為其文件內(nèi)容即可,在本例中就分為設(shè)置為1和2。其他配置具體含義可見(jiàn)官方文檔。

3)啟動(dòng)集群環(huán)境

分別在各服務(wù)器下運(yùn)行zookeeper啟動(dòng)腳本

/home/admin/zookeeper-3.2.2/bin/zkServer.sh start

4)應(yīng)用zookeeper

應(yīng)用zookeeper可以在是shell中執(zhí)行命令,也可以在java或c中調(diào)用程序接口。

在shell中執(zhí)行命令,可運(yùn)行以下命令:

bin/zkCli.sh -server 10.20.147.35:2181

其中 10.20.147.35為集群中任一臺(tái)機(jī)器的ip或機(jī)器名。執(zhí)行后可進(jìn)入zookeeper的操作面板,具體如何操作可見(jiàn)官方文檔

在java中通過(guò)調(diào)用程序接口來(lái)應(yīng)用zookeeper較為復(fù)雜一點(diǎn),需要了解watch和callback等概念,不過(guò)試驗(yàn)最簡(jiǎn)單的CURD倒不需要這些,只需要使用ZooKeeper這個(gè)類(lèi)即可,具體測(cè)試代碼如下:

public static void main(String[] args) {  
    try {  
        ZooKeeper zk = new ZooKeeper("10.20.147.35:2181", 30000, null);  
        String name = zk.create("/company", "alibaba".getBytes(),  
                Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);  
        Stat stat = new Stat();  
        System.out.println(new String(zk.getData(name, null, stat)));  
        zk.setData(name, "taobao".getBytes(), stat.getVersion(), null, null);  
        System.out.println(new String(zk.getData(name, null, stat)));  
        stat = zk.exists(name, null);  
        zk.delete(name, stat.getVersion(), null, null);  
        System.out.println(new String(zk.getData(name, null, stat)));  
    } catch (Exception e) {  
        e.printStackTrace();  
    }  

public static void main(String[] args) {
 try {
  ZooKeeper zk = new ZooKeeper("10.20.147.35:2181", 30000, null);
  String name = zk.create("/company", "alibaba".getBytes(),
                Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
  Stat stat = new Stat();
  System.out.println(new String(zk.getData(name, null, stat)));
  zk.setData(name, "taobao".getBytes(), stat.getVersion(), null, null);
  System.out.println(new String(zk.getData(name, null, stat)));
  stat = zk.exists(name, null);
        zk.delete(name, stat.getVersion(), null, null);
        System.out.println(new String(zk.getData(name, null, stat)));
 } catch (Exception e) {
  e.printStackTrace();
 }

以上代碼比較簡(jiǎn)單,查看一下zooKeeper的api doc就知道如何使用了

ZooKeeper的實(shí)現(xiàn)機(jī)理

ZooKeeper的實(shí)現(xiàn)機(jī)理是我看過(guò)的開(kāi)源框架中最復(fù)雜的,它的解決是分布式環(huán)境中的一致性問(wèn)題,這個(gè)場(chǎng)景也決定了其實(shí)現(xiàn)的復(fù)雜性??戳藘扇斓脑创a還是有些摸不著頭腦,有些超出了我的能力,不過(guò)通過(guò)看文檔和其他高人寫(xiě)的文章大致清楚它的原理和基本結(jié)構(gòu)。

1)ZooKeeper的基本原理

ZooKeeper是以Fast Paxos算法為基礎(chǔ)的,在前一篇 blog 中大致介紹了一下paxos,而沒(méi)有提到的是paxos存在活鎖的問(wèn)題,也就是當(dāng)有多個(gè) proposer交錯(cuò)提交時(shí),有可能互相排斥導(dǎo)致沒(méi)有一個(gè)proposer能提交成功,而Fast Paxos作了一些優(yōu)化,通過(guò)選舉產(chǎn)生一個(gè)leader,只有l(wèi)eader才能提交propose,具體算法可見(jiàn)Fast Paxos 。因此,要想弄得ZooKeeper首先得對(duì)Fast Paxos有所了解。

2)ZooKeeper的基本運(yùn)轉(zhuǎn)流程

ZooKeeper主要存在以下兩個(gè)流程:

選舉Leader
同步數(shù)據(jù)
選舉Leader過(guò)程中算法有很多,但要達(dá)到的選舉標(biāo)準(zhǔn)是一致的:

Leader要具有最高的zxid 
集群中大多數(shù)的機(jī)器得到響應(yīng)并follow選出的Leader
同步數(shù)據(jù)這個(gè)流程是ZooKeeper的精髓所在,并且就是Fast Paxos算法的具體實(shí)現(xiàn)。一個(gè)牛人畫(huà)了一個(gè)ZooKeeper數(shù)據(jù)流動(dòng)圖,比較直觀地描述了ZooKeeper是如何同步數(shù)據(jù)的。

 

以上兩個(gè)核心流程我暫時(shí)還不能悟透其中的精髓,這也和我還沒(méi)有完全理解Fast Paxos算法有關(guān),有待后續(xù)深入學(xué)習(xí)

ZooKeeper的應(yīng)用領(lǐng)域

Tim在blog中提到了Paxos所能應(yīng)用的幾個(gè)主要場(chǎng)景,包括database replication、naming service、config配置管理、access control list等等,這也是ZooKeeper可以應(yīng)用的幾個(gè)主要場(chǎng)景。此外, ZooKeeper官方文檔中提到了幾個(gè)更為基礎(chǔ)的分布式應(yīng)用,這也算是ZooKeeper的妙用吧

1)分布式Barrier

Barrier是一種控制和協(xié)調(diào)多個(gè)任務(wù)觸發(fā)次序的機(jī)制,簡(jiǎn)單說(shuō)來(lái)就是搞個(gè)閘門(mén)把欲執(zhí)行的任務(wù)給攔住,等所有任務(wù)都處于可以執(zhí)行的狀態(tài)時(shí),才放開(kāi)閘門(mén)。它的機(jī)理可以見(jiàn)下圖所示:

 

在單機(jī)上JDK提供了CyclicBarrier這個(gè)類(lèi)來(lái)實(shí)現(xiàn)這個(gè)機(jī)制,但在分布式環(huán)境中JDK就無(wú)能為力了。在分布式里實(shí)現(xiàn)Barrer需要高一致性做保障,因此 ZooKeeper可以派上用場(chǎng),所采取的方案就是用一個(gè)Node作為Barrer的實(shí)體,需要被Barrer的任務(wù)通過(guò)調(diào)用exists()檢測(cè)這個(gè)Node的存在,當(dāng)需要打開(kāi)Barrier的時(shí)候,刪掉這個(gè)Node,ZooKeeper的watch機(jī)制會(huì)通知到各個(gè)任務(wù)可以開(kāi)始執(zhí)行。

2) 分布式 Queue

與 Barrier類(lèi)似 分布式環(huán)境中 實(shí)現(xiàn)Queue也需要高一致性做保障, ZooKeeper提供了一個(gè)種簡(jiǎn)單的方式, ZooKeeper通過(guò)一個(gè)Node來(lái)維護(hù)Queue的實(shí)體,用其children來(lái)存儲(chǔ)Queue的內(nèi)容,并且 ZooKeeper的create方法中提供了順序遞增的模式,會(huì)自動(dòng)地在name后面加上一個(gè)遞增的數(shù)字來(lái)插入新元素。可以用其 children來(lái)構(gòu)建一個(gè)queue的數(shù)據(jù)結(jié)構(gòu),offer的時(shí)候使用create,take的時(shí)候按照children的順序刪除第一個(gè)即可。 ZooKeeper保障了各個(gè)server上數(shù)據(jù)是一致的,因此也就實(shí)現(xiàn)了一個(gè) 分布式 Queue。take和offer的實(shí)例代碼如下所示:

/** 
 * Removes the head of the queue and returns it, blocks until it succeeds. 
 * @return The former head of the queue 
 * @throws NoSuchElementException 
 * @throws KeeperException 
 * @throws InterruptedException 
 */ 
public byte[] take() throws KeeperException, InterruptedException {  
    TreeMap<Long,String> orderedChildren;  
    // Same as for element.  Should refactor this.  
    while(true){  
        LatchChildWatcher childWatcher = new LatchChildWatcher();  
        try{  
            orderedChildren = orderedChildren(childWatcher);  
        }catch(KeeperException.NoNodeException e){  
            zookeeper.create(dir, new byte[0], acl, CreateMode.PERSISTENT);  
            continue;  
        }  
        if(orderedChildren.size() == 0){  
            childWatcher.await();  
            continue;  
        }  
        for(String headNode : orderedChildren.values()){  
            String path = dir +"/"+headNode;  
            try{  
                byte[] data = zookeeper.getData(path, false, null);  
                zookeeper.delete(path, -1);  
                return data;  
            }catch(KeeperException.NoNodeException e){  
                // Another client deleted the node first.  
            }  
        }  
    }  
}  
/** 
 * Inserts data into queue. 
 * @param data 
 * @return true if data was successfully added 
 */ 
public boolean offer(byte[] data) throws KeeperException, InterruptedException{  
    for(;;){  
        try{  
            zookeeper.create(dir+"/"+prefix, data, acl, CreateMode.PERSISTENT_SEQUENTIAL);  
            return true;  
        }catch(KeeperException.NoNodeException e){  
            zookeeper.create(dir, new byte[0], acl, CreateMode.PERSISTENT);  
        }  
    }  

/**
 * Removes the head of the queue and returns it, blocks until it succeeds.
 * @return The former head of the queue
 * @throws NoSuchElementException
 * @throws KeeperException
 * @throws InterruptedException
 */
public byte[] take() throws KeeperException, InterruptedException {
    TreeMap<Long,String> orderedChildren;
    // Same as for element.  Should refactor this.
    while(true){
        LatchChildWatcher childWatcher = new LatchChildWatcher();
        try{
            orderedChildren = orderedChildren(childWatcher);
        }catch(KeeperException.NoNodeException e){
            zookeeper.create(dir, new byte[0], acl, CreateMode.PERSISTENT);
            continue;
        }
        if(orderedChildren.size() == 0){
            childWatcher.await();
            continue;
        }
        for(String headNode : orderedChildren.values()){
            String path = dir +"/"+headNode;
            try{
                byte[] data = zookeeper.getData(path, false, null);
                zookeeper.delete(path, -1);
                return data;
            }catch(KeeperException.NoNodeException e){
                // Another client deleted the node first.
            }
        }
    }
}
/**
 * Inserts data into queue.
 * @param data
 * @return true if data was successfully added
 */
public boolean offer(byte[] data) throws KeeperException, InterruptedException{
    for(;;){
        try{
            zookeeper.create(dir+"/"+prefix, data, acl, CreateMode.PERSISTENT_SEQUENTIAL);
            return true;
        }catch(KeeperException.NoNodeException e){
            zookeeper.create(dir, new byte[0], acl, CreateMode.PERSISTENT);
        }
    }
}

3)分布式lock

利用 ZooKeeper實(shí)現(xiàn) 分布式lock,主要是通過(guò)一個(gè)Node來(lái)代表一個(gè)Lock,當(dāng)一個(gè)client去拿鎖的時(shí)候,會(huì)在這個(gè)Node下創(chuàng)建一個(gè)自增序列的child,然后通過(guò)getChildren()方式來(lái)check創(chuàng)建的child是不是最靠前的,如果是則拿到鎖,否則就調(diào)用exist()來(lái)check第二靠前的child,并加上watch來(lái)監(jiān)視。當(dāng)拿到鎖的child執(zhí)行完后歸還鎖,歸還鎖僅僅需要?jiǎng)h除自己創(chuàng)建的child,這時(shí)watch機(jī)制會(huì)通知到所有沒(méi)有拿到鎖的client,這些child就會(huì)根據(jù)前面所講的拿鎖規(guī)則來(lái)競(jìng)爭(zhēng)鎖。

 

本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/cutesource/archive/2010/08/18/5822459.aspx

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多