隨筆-7  評(píng)論-23  文章-0  trackbacks-0
            2010年9月30日

          去年年底,團(tuán)隊(duì)內(nèi)部成員分享了這篇google論文,初讀了下,發(fā)現(xiàn)其有蠻多有意思的東西,就想把他翻譯下來,但是翻譯了一小部分,明顯感覺如果這樣的翻譯發(fā)出去,很可能誤人子弟,所以改成了概要式的博文,這篇文章會(huì)將原論文最核心的幾個(gè)部分做不完全的翻譯和個(gè)人理解,如有不解或者錯(cuò)誤的地方,請(qǐng)查看原論文,并希望能夠指正,謝謝.

          正文

          Megastore是谷歌一個(gè)內(nèi)部的存儲(chǔ)系統(tǒng),它的底層數(shù)據(jù)存儲(chǔ)依賴Bigtable,也就是基于NoSql實(shí)現(xiàn)的,但是和傳統(tǒng)的NoSql不同的是,它實(shí)現(xiàn)了類似RDBMS的數(shù)據(jù)模型(便捷性),同時(shí)提供數(shù)據(jù)的強(qiáng)一致性解決方案(同一個(gè)datacenter,基于MVCC的事務(wù)實(shí)現(xiàn)),并且將數(shù)據(jù)進(jìn)行細(xì)顆粒度的分區(qū)(這里的分區(qū)是指在同一個(gè)datacenter,所有datacenter都有相同的分區(qū)數(shù)據(jù)),然后將數(shù)據(jù)更新在機(jī)房間進(jìn)行同步復(fù)制(這個(gè)保證所有datacenter中的數(shù)據(jù)一致).

          ...

          中文翻譯地址: http://wenku.baidu.com/view/a465cc260722192e4536f671.html#

          原文地址: http://wenku.baidu.com/view/2ddeb1afdd3383c4bb4cd2bb.html

          posted @ 2011-02-14 12:44 BucketLI 閱讀(3191) | 評(píng)論 (1)編輯 收藏

          zookeeper介紹
          zookeeper是一個(gè)為分布式應(yīng)用提供一致性服務(wù)的軟件,它是開源的Hadoop項(xiàng)目中的一個(gè)子項(xiàng)目,并且根據(jù)google發(fā)表的<The Chubby lock service for loosely-coupled distributed systems>論文來實(shí)現(xiàn)的,接下來我們首先來安裝使用下這個(gè)軟件,然后再來探索下其中比較重要一致性算法。  

          zookeeper安裝和使用
          zookeeper的安裝基本上可以按照 http://hadoop.apache.org/zookeeper/docs/current/ zookeeperStarted.html 這個(gè)頁(yè)面上的步驟完成安裝,這里主要介紹下部署一個(gè)集群的步驟,因?yàn)檫@個(gè)官方頁(yè)面似乎講得并不是非常詳細(xì)(Running Replicated Zookeeper)

          由于手頭機(jī)器不足,所以在一臺(tái)機(jī)器上部署了
          3個(gè)server,如果你手頭也比較緊,也可以這么做。那么我建了3個(gè)文件夾,如下
          server1   server2   server3

          然后每個(gè)文件夾里面解壓一個(gè)
          zookeeper的下載包,并且還建了幾個(gè)文件夾,總體結(jié)構(gòu)如下,最后那個(gè)是下載過來壓縮包的解壓文件
          data dataLog logs zookeeper-3.3.2

          那么首先進(jìn)入data目錄,創(chuàng)建一個(gè)myid的文件,里面寫入一個(gè)數(shù)字,比如我這個(gè)是server1,那么就寫一個(gè)1server2對(duì)應(yīng)myid文件就寫入2server3對(duì)應(yīng)myid文件就寫個(gè)3

          然后進(jìn)入zookeeper-3.3.2/conf目錄,那么如果是剛下過來,會(huì)有3個(gè)文件,configuration.xml, log4j.properties,zoo_sample.cfg,3個(gè)文件我們首先要做的就是在這個(gè)目錄創(chuàng)建一個(gè)zoo.cfg的配置文件,當(dāng)然你可以把zoo_sample.cfg文件改成zoo.cfg,配置的內(nèi)容如下所示: 
          tickTime=2000
          initLimit=5
          syncLimit=2
          dataDir=xxxx/zookeeper/server1/data
          dataLogDir=xxx/zookeeper/server1/dataLog
          clientPort=2181
          server.1=127.0.0.1:2888:3888
          server.2=127.0.0.1:2889:3889
          server.3=127.0.0.1:2890:3890

          標(biāo)紅的幾個(gè)配置應(yīng)該官網(wǎng)講得很清楚了,只是需要注意的是clientPort這個(gè)端口如果你是在1臺(tái)機(jī)器上部署多個(gè)server,那么每臺(tái)機(jī)器都要不同的clientPort,比如我server12181,server22182server32183dataDirdataLogDir也需要區(qū)分下。

          最后幾行唯一需要注意的地方就是 server.X 這個(gè)數(shù)字就是對(duì)應(yīng) data/myid中的數(shù)字。你在3個(gè)servermyid文件中分別寫入了123,那么每個(gè)server中的zoo.cfg都配server.1,server.2,server.3OK了。因?yàn)樵谕慌_(tái)機(jī)器上,后面連著的2個(gè)端口3個(gè)server都不要一樣,否則端口沖突,其中第一個(gè)端口用來集群成員的信息交換,第二個(gè)端口是在leader掛掉時(shí)專門用來進(jìn)行選舉leader所用。

          進(jìn)入zookeeper-3.3.2/bin 目錄中./zkServer.sh start啟動(dòng)一個(gè)server,這時(shí)會(huì)報(bào)大量錯(cuò)誤?其實(shí)沒什么關(guān)系,因?yàn)楝F(xiàn)在集群只起了1臺(tái)serverzookeeper服務(wù)器端起來會(huì)根據(jù)zoo.cfg的服務(wù)器列表發(fā)起選舉leader的請(qǐng)求,因?yàn)檫B不上其他機(jī)器而報(bào)錯(cuò),那么當(dāng)我們起第二個(gè)zookeeper實(shí)例后,leader將會(huì)被選出,從而一致性服務(wù)開始可以使用,這是因?yàn)?/span>3臺(tái)機(jī)器只要有2臺(tái)可用就可以選出leader并且對(duì)外提供服務(wù)(2n+1臺(tái)機(jī)器,可以容n臺(tái)機(jī)器掛掉)

          接下來就可以使用了,我們可以先通過 zookeeper自帶的客戶端交互程序來簡(jiǎn)單感受下zookeeper到底做一些什么事情。進(jìn)入zookeeper-3.3.2/bin3個(gè)server中任意一個(gè))下,./zkCli.sh –server 127.0.0.1:2182,我連的是開著2182端口的機(jī)器。

          那么,首先我們隨便打個(gè)命令,因?yàn)?/span>zookeeper不認(rèn)識(shí),他會(huì)給出命令的help,如下圖
            
            
          ls(查看當(dāng)前節(jié)點(diǎn)數(shù)據(jù)),
          ls2(查看當(dāng)前節(jié)點(diǎn)數(shù)據(jù)并能看到更新次數(shù)等數(shù)據(jù)) ,
          create(創(chuàng)建一個(gè)節(jié)點(diǎn)) ,
          get(得到一個(gè)節(jié)點(diǎn),包含數(shù)據(jù)和更新次數(shù)等數(shù)據(jù)),
          set(修改節(jié)點(diǎn))
          delete(刪除一個(gè)節(jié)點(diǎn))

          通過上述命令實(shí)踐,我們可以發(fā)現(xiàn),zookeeper使用了一個(gè)類似文件系統(tǒng)的樹結(jié)構(gòu),數(shù)據(jù)可以掛在某個(gè)節(jié)點(diǎn)上,可以對(duì)這個(gè)節(jié)點(diǎn)進(jìn)行刪改。另外我們還發(fā)現(xiàn),當(dāng)改動(dòng)一個(gè)節(jié)點(diǎn)的時(shí)候,集群中活著的機(jī)器都會(huì)更新到一致的數(shù)據(jù)。

          zookeeper的數(shù)據(jù)模型
          在簡(jiǎn)單使用了zookeeper之后,我們發(fā)現(xiàn)其數(shù)據(jù)模型有些像操作系統(tǒng)的文件結(jié)構(gòu),結(jié)構(gòu)如下圖所示



          (1)     每個(gè)節(jié)點(diǎn)在zookeeper中叫做znode,并且其有一個(gè)唯一的路徑標(biāo)識(shí),如/SERVER2節(jié)點(diǎn)的標(biāo)識(shí)就為/APP3/SERVER2
          (2)     Znode可以有子znode,并且znode里可以存數(shù)據(jù),但是EPHEMERAL類型的節(jié)點(diǎn)不能有子節(jié)點(diǎn)
          (3)     Znode中的數(shù)據(jù)可以有多個(gè)版本,比如某一個(gè)路徑下存有多個(gè)數(shù)據(jù)版本,那么查詢這個(gè)路徑下的數(shù)據(jù)就需要帶上版本。
          (4)     znode 可以是臨時(shí)節(jié)點(diǎn),一旦創(chuàng)建這個(gè) znode 的客戶端與服務(wù)器失去聯(lián)系,這個(gè) znode 也將自動(dòng)刪除,Zookeeper 的客戶端和服務(wù)器通信采用長(zhǎng)連接方式,每個(gè)客戶端和  服務(wù)器通過心跳來保持連接,這個(gè)連接狀態(tài)稱為 session,如果 znode 是臨時(shí)節(jié)點(diǎn),這個(gè) session 失效,znode 也就刪除了
          (5)     znode 的目錄名可以自動(dòng)編號(hào),如 App1 已經(jīng)存在,再創(chuàng)建的話,將會(huì)自動(dòng)命名為 App2 
          (6)     znode 可以被監(jiān)控,包括這個(gè)目錄節(jié)點(diǎn)中存儲(chǔ)的數(shù)據(jù)的修改,子節(jié)點(diǎn)目錄的變化等,一旦變化可以通知設(shè)置監(jiān)控的客戶端,這個(gè)功能是zookeeper對(duì)于應(yīng)用最重要的特性,通過這個(gè)特性可以實(shí)現(xiàn)的功能包括配置的集中管理,集群管理,分布式鎖等等。
           

          通過java代碼使用zookeeper 
          Zookeeper的使用主要是通過創(chuàng)建其jar包下的Zookeeper實(shí)例,并且調(diào)用其接口方法進(jìn)行的,主要的操作就是對(duì)znode的增刪改操作,監(jiān)聽znode的變化以及處理。 

          以下為主要的API使用和解釋

          //創(chuàng)建一個(gè)Zookeeper實(shí)例,第一個(gè)參數(shù)為目標(biāo)服務(wù)器地址和端口,第二個(gè)參數(shù)為Session超時(shí)時(shí)間,第三個(gè)為節(jié)點(diǎn)變化時(shí)的回調(diào)方法
          ZooKeeper zk = new ZooKeeper("127.0.0.1:2181"500000,new Watcher() {
                     
          // 監(jiān)控所有被觸發(fā)的事件
                       public void process(WatchedEvent event) {
                     
          //dosomething
                     }

                }
          );
          //創(chuàng)建一個(gè)節(jié)點(diǎn)root,數(shù)據(jù)是mydata,不進(jìn)行ACL權(quán)限控制,節(jié)點(diǎn)為永久性的(即客戶端shutdown了也不會(huì)消失)
          zk.create("/root""mydata".getBytes(),Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

          //在root下面創(chuàng)建一個(gè)childone znode,數(shù)據(jù)為childone,不進(jìn)行ACL權(quán)限控制,節(jié)點(diǎn)為永久性的
          zk.create("/root/childone","childone".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);

          //取得/root節(jié)點(diǎn)下的子節(jié)點(diǎn)名稱,返回List<String>
          zk.getChildren("/root",true);

          //取得/root/childone節(jié)點(diǎn)下的數(shù)據(jù),返回byte[]
          zk.getData("/root/childone"truenull);

          //修改節(jié)點(diǎn)/root/childone下的數(shù)據(jù),第三個(gè)參數(shù)為版本,如果是-1,那會(huì)無視被修改的數(shù)據(jù)版本,直接改掉
          zk.setData("/root/childone","childonemodify".getBytes(), -1);

          //刪除/root/childone這個(gè)節(jié)點(diǎn),第二個(gè)參數(shù)為版本,-1的話直接刪除,無視版本
          zk.delete("/root/childone"-1);
                
          //關(guān)閉session
          zk.close();
           
          Zookeeper的主流應(yīng)用場(chǎng)景實(shí)現(xiàn)思路(除去官方示例)

          (1)
          配置管理
          集中式的配置管理在應(yīng)用集群中是非常常見的,一般商業(yè)公司內(nèi)部都會(huì)實(shí)現(xiàn)一套集中的配置管理中心,應(yīng)對(duì)不同的應(yīng)用集群對(duì)于共享各自配置的需求,并且在配置變更時(shí)能夠通知到集群中的每一個(gè)機(jī)器。

          Zookeeper
          很容易實(shí)現(xiàn)這種集中式的配置管理,比如將APP1的所有配置配置到/APP1 znode下,APP1所有機(jī)器一啟動(dòng)就對(duì)/APP1這個(gè)節(jié)點(diǎn)進(jìn)行監(jiān)控(zk.exist("/APP1",true)),并且實(shí)現(xiàn)回調(diào)方法Watcher,那么在zookeeper/APP1 znode節(jié)點(diǎn)下數(shù)據(jù)發(fā)生變化的時(shí)候,每個(gè)機(jī)器都會(huì)收到通知,Watcher方法將會(huì)被執(zhí)行,那么應(yīng)用再取下數(shù)據(jù)即可(zk.getData("/APP1",false,null));

          以上這個(gè)例子只是簡(jiǎn)單的粗顆粒度配置監(jiān)控,細(xì)顆粒度的數(shù)據(jù)可以進(jìn)行分層級(jí)監(jiān)控,這一切都是可以設(shè)計(jì)和控制的。
              
          (2)集群管理
          應(yīng)用集群中,我們常常需要讓每一個(gè)機(jī)器知道集群中(或依賴的其他某一個(gè)集群)哪些機(jī)器是活著的,并且在集群機(jī)器因?yàn)殄礄C(jī),網(wǎng)絡(luò)斷鏈等原因能夠不在人工介入的情況下迅速通知到每一個(gè)機(jī)器。

          Zookeeper
          同樣很容易實(shí)現(xiàn)這個(gè)功能,比如我在zookeeper服務(wù)器端有一個(gè)znode/APP1SERVERS,那么集群中每一個(gè)機(jī)器啟動(dòng)的時(shí)候都去這個(gè)節(jié)點(diǎn)下創(chuàng)建一個(gè)EPHEMERAL類型的節(jié)點(diǎn),比如server1創(chuàng)建/APP1SERVERS/SERVER1(可以使用ip,保證不重復(fù))server2創(chuàng)建/APP1SERVERS/SERVER2,然后SERVER1SERVER2watch /APP1SERVERS這個(gè)父節(jié)點(diǎn),那么也就是這個(gè)父節(jié)點(diǎn)下數(shù)據(jù)或者子節(jié)點(diǎn)變化都會(huì)通知對(duì)該節(jié)點(diǎn)進(jìn)行watch的客戶端。因?yàn)?/span>EPHEMERAL類型節(jié)點(diǎn)有一個(gè)很重要的特性,就是客戶端和服務(wù)器端連接斷掉或者session過期就會(huì)使節(jié)點(diǎn)消失,那么在某一個(gè)機(jī)器掛掉或者斷鏈的時(shí)候,其對(duì)應(yīng)的節(jié)點(diǎn)就會(huì)消失,然后集群中所有對(duì)/APP1SERVERS進(jìn)行watch的客戶端都會(huì)收到通知,然后取得最新列表即可。

          另外有一個(gè)應(yīng)用場(chǎng)景就是集群選
          master,一旦master掛掉能夠馬上能從slave中選出一個(gè)master,實(shí)現(xiàn)步驟和前者一樣,只是機(jī)器在啟動(dòng)的時(shí)候在APP1SERVERS創(chuàng)建的節(jié)點(diǎn)類型變?yōu)?/span>EPHEMERAL_SEQUENTIAL類型,這樣每個(gè)節(jié)點(diǎn)會(huì)自動(dòng)被編號(hào),例如          
          zk.create("/testRootPath/testChildPath1","1".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);
                  
          zk.create(
          "/testRootPath/testChildPath2","2".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);
                  
          zk.create(
          "/testRootPath/testChildPath3","3".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);
                  
          // 創(chuàng)建一個(gè)子目錄節(jié)點(diǎn)
          zk.create("/testRootPath/testChildPath4","4".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);

          System.out.println(zk.getChildren(
          "/testRootPath"false));
           打印結(jié)果:[testChildPath10000000000, testChildPath20000000001, testChildPath40000000003, testChildPath30000000002]

          zk.create("/testRootPath""testRootData".getBytes(),Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

          // 創(chuàng)建一個(gè)子目錄節(jié)點(diǎn)
          zk.create("/testRootPath/testChildPath1","1".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);
                  
          zk.create(
          "/testRootPath/testChildPath2","2".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);
                  
          zk.create(
          "/testRootPath/testChildPath3","3".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);
                  
          // 創(chuàng)建一個(gè)子目錄節(jié)點(diǎn)
          zk.create("/testRootPath/testChildPath4","4".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);

          System.out.println(zk.getChildren(
          "/testRootPath"false));
          打印結(jié)果:[testChildPath2, testChildPath1, testChildPath4, testChildPath3]

          我們默認(rèn)規(guī)定編號(hào)最小的為
          master,所以當(dāng)我們對(duì)/APP1SERVERS節(jié)點(diǎn)做監(jiān)控的時(shí)候,得到服務(wù)器列表,只要所有集群機(jī)器邏輯認(rèn)為最小編號(hào)節(jié)點(diǎn)為master,那么master就被選出,而這個(gè)master宕機(jī)的時(shí)候,相應(yīng)的znode會(huì)消失,然后新的服務(wù)器列表就被推送到客戶端,然后每個(gè)節(jié)點(diǎn)邏輯認(rèn)為最小編號(hào)節(jié)點(diǎn)為master,這樣就做到動(dòng)態(tài)master選舉。


          總結(jié) 

          我們初步使用了一下zookeeper并且嘗試著描述了幾種應(yīng)用場(chǎng)景的具體實(shí)現(xiàn)思路,接下來的文章,我們會(huì)嘗試著去探究一下zookeeper的高可用性與leaderElection算法。

          參考http://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/

                http://hadoop.apache.org/zookeeper/docs/current/

                http://rdc.taobao.com/team/jm/archives/448

          posted @ 2010-12-21 18:58 BucketLI 閱讀(118571) | 評(píng)論 (15)編輯 收藏
               摘要:  1.       ExecutorService  Java從1.5開始正式提供了并發(fā)包,而這個(gè)并發(fā)包里面除了原子變量,synchronizer,并發(fā)容器,另外一個(gè)非常重要的特性就是線程池.對(duì)于線程池的意義,我們這邊不再多說. 上圖是線程池的主體類圖,ThreadPoolExecutor是應(yīng)用最為廣泛的一個(gè)...  閱讀全文
          posted @ 2010-12-16 13:57 BucketLI 閱讀(5072) | 評(píng)論 (0)編輯 收藏
               摘要: 1.       java.util.concurrent所提供的并發(fā)容器 java.util.concurrent提供了多種并發(fā)容器,總體上來說有4類,隊(duì)列類型的BlockingQueue和 ConcurrentLinkedQueue,Map類型的ConcurrentMap,Set類型的ConcurrentSkipListSet和Co...  閱讀全文
          posted @ 2010-11-25 13:43 BucketLI 閱讀(5172) | 評(píng)論 (3)編輯 收藏
               摘要: 最近需要用到log4j動(dòng)態(tài)定制Logger的場(chǎng)景,然后加上以前對(duì)于這個(gè)日志工具拿來就用而不知其原理的原因,所以決定花點(diǎn)時(shí)間看下它的源碼,如果你還對(duì)log4j如何使用感到困惑,那么請(qǐng)首先簡(jiǎn)要瀏覽下它的官網(wǎng)http://logging.apache.org/log4j/ Log4j總體來說是一個(gè)可定制,支持同時(shí)多種形式輸出日志,并且高度結(jié)構(gòu)化的日志庫(kù)。可定制,也就是既可以通過log4j.prop...  閱讀全文
          posted @ 2010-10-22 10:40 BucketLI 閱讀(4288) | 評(píng)論 (1)編輯 收藏
               摘要: JAVA LOCK總體來說關(guān)鍵要素主要包括3點(diǎn): 1.unsafe.compareAndSwapXXX(Object o,long offset,int expected,int x) 2.unsafe.park() 和 unsafe.unpark() 3.單向鏈表結(jié)構(gòu)或者說存儲(chǔ)線程的數(shù)據(jù)結(jié)構(gòu) 第1點(diǎn)主要為了保證鎖的原子性,相當(dāng)于一個(gè)鎖是否正在被使用的標(biāo)記,并且比較和設(shè)置這個(gè)標(biāo)記的操...  閱讀全文
          posted @ 2010-09-30 12:05 BucketLI 閱讀(13158) | 評(píng)論 (2)編輯 收藏
          主站蜘蛛池模板: 巨鹿县| 仲巴县| 红河县| 镇巴县| 陕西省| 巨野县| 高邮市| 罗平县| 阿克苏市| 丹阳市| 柘荣县| 益阳市| 昌乐县| 翁牛特旗| 金塔县| 辽阳县| 平山县| 墨脱县| 如皋市| 蒲江县| 双鸭山市| 方山县| 沅江市| 读书| 永新县| 灵寿县| 庆元县| 高州市| 承德市| 集安市| 十堰市| 揭西县| 广西| 白沙| 沙雅县| 碌曲县| 巫溪县| 新郑市| 绩溪县| 芮城县| 盐城市|