国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

分布式設計與開發(fā)(三)------高一致性服務ZooKeeper

2019-11-14 15:24:20
字體:
供稿:網(wǎng)友

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

  • 高可用性
  • 高一致性
  • 高性能

對于這種有些挑戰(zhàn)CAP原則 的服務該如何設計,是一個挑戰(zhàn),也是一個不錯的研究課題,Apache的ZooKeeper也許給了我們一個不錯的答案。ZooKeeper是一個分布式的,開放源碼的分布式應用程序協(xié)調(diào)服務, 它暴露了一個簡單的原語集,分布式應用程序可以基于它實現(xiàn)同步服務,配置維護和命名服務等。關于ZooKeeper更多信息可以參見 官方文檔

ZooKeeper的基本使用

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

1)在各服務器安裝 ZooKeeper

下載ZooKeeper后在各服務器上進行解壓即可

tar -xzf zookeeper-3.2.2.tar.gz

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

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

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

 

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

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

分別在各服務器下運行zookeeper啟動腳本

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

4)應用zookeeper

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

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

bin/zkCli.sh -server 10.20.147.35:2181

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

在java中通過調(diào)用程序接口來應用zookeeper較為復雜一點,需要了解watch和callback等概念,不過試驗最簡單的CURD倒不需要這些,只需要使用ZooKeeper這個類即可,具體測試代碼如下:

[java] view plaincopy
  1. public static void main(String[] args) {  
  2.     try {  
  3.         ZooKeeper zk = new ZooKeeper("10.20.147.35:2181", 30000, null);  
  4.         String name = zk.create("/company", "alibaba".getBytes(),  
  5.                 Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);  
  6.         Stat stat = new Stat();  
  7.         System.out.PRintln(new String(zk.getData(name, null, stat)));  
  8.         zk.setData(name, "taobao".getBytes(), stat.getVersion(), null, null);  
  9.         System.out.println(new String(zk.getData(name, null, stat)));  
  10.         stat = zk.exists(name, null);  
  11.         zk.delete(name, stat.getVersion(), null, null);  
  12.         System.out.println(new String(zk.getData(name, null, stat)));  
  13.     } catch (Exception e) {  
  14.         e.printStackTrace();  
  15.     }  
  16. }  

 

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

ZooKeeper的實現(xiàn)機理

ZooKeeper的實現(xiàn)機理是我看過的開源框架中最復雜的,它的解決是分布式環(huán)境中的一致性問題,這個場景也決定了其實現(xiàn)的復雜性。看了兩三天的源碼還是有些摸不著頭腦,有些超出了我的能力,不過通過看文檔和其他高人寫的文章大致清楚它的原理和基本結(jié)構(gòu)。

1)ZooKeeper的基本原理

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

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

ZooKeeper主要存在以下兩個流程:

  • 選舉Leader
  • 同步數(shù)據(jù)

選舉Leader過程中算法有很多,但要達到的選舉標準是一致的:

  • Leader要具有最高的zxid 
  • 集群中大多數(shù)的機器得到響應并follow選出的Leader

同步數(shù)據(jù)這個流程是ZooKeeper的精髓所在,并且就是Fast Paxos算法的具體實現(xiàn)。一個牛人畫了一個ZooKeeper數(shù)據(jù)流動圖,比較直觀地描述了ZooKeeper是如何同步數(shù)據(jù)的。

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

ZooKeeper的應用領域

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

1)分布式Barrier

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

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

2) 分布式 Queue

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

 

[java] view plaincopy
  1. /** 
  2.  * Removes the head of the queue and returns it, blocks until it succeeds. 
  3.  * @return The former head of the queue 
  4.  * @throws NoSuchElementException 
  5.  * @throws KeeperException 
  6.  * @throws InterruptedException 
  7.  */  
  8. public byte[] take() throws KeeperException, InterruptedException {  
  9.     TreeMap<Long,String> orderedChildren;  
  10.     // Same as for element.  Should refactor this.  
  11.     while(true){  
  12.         LatchChildWatcher childWatcher = new LatchChildWatcher();  
  13.         try{  
  14.             orderedChildren = orderedChildren(childWatcher);  
  15.         }catch(KeeperException.NoNodeException e){  
  16.             zookeeper.create(dir, new byte[0], acl, CreateMode.PERSISTENT);  
  17.             continue;  
  18.         }  
  19.         if(orderedChildren.size() == 0){  
  20.             childWatcher.await();  
  21.             continue;  
  22.         }  
  23.         for(String headNode : orderedChildren.values()){  
  24.             String path = dir +"/"+headNode;  
  25.             try{  
  26.                 byte[] data = zookeeper.getData(path, false, null);  
  27.                 zookeeper.delete(path, -1);  
  28.                 return data;  
  29.             }catch(KeeperException.NoNodeException e){  
  30.                 // Another client deleted the node first.  
  31.             }  
  32.         }  
  33.     }  
  34. }  
  35. /** 
  36.  * Inserts data into queue. 
  37.  * @param data 
  38.  * @return true if data was successfully added 
  39.  */  
  40. public boolean offer(byte[] data) throws KeeperException, InterruptedException{  
  41.     for(;;){  
  42.         try{  
  43.             zookeeper.create(dir+"/"+prefix, data, acl, CreateMode.PERSISTENT_SEQUENTIAL);  
  44.             return true;  
  45.         }catch(KeeperException.NoNodeException e){  
  46.             zookeeper.create(dir, new byte[0], acl, CreateMode.PERSISTENT);  
  47.         }  
  48.     }  
  49. }  

3)分布式lock

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


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 新乐市| 青海省| 寿宁县| 延长县| 贡觉县| 崇左市| 调兵山市| 阿勒泰市| 孝感市| 保康县| 修武县| 合作市| 祥云县| 鄂州市| 左权县| 威远县| 青州市| 苏州市| 伊春市| 东港市| 改则县| 巴中市| 广德县| 石楼县| 舟曲县| 阿拉善盟| 观塘区| 高阳县| 伊川县| 淅川县| 遵义县| 桐梓县| 钟山县| 林西县| 昌吉市| 武穴市| 汝阳县| 紫金县| 台中县| 白沙| 天柱县|