分布式設(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算法 1)問(wèn)題描述
當(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)受影響盡可能小 以上兩個(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ù)有以下要求: 高可用性 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 其中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) { 以上代碼比較簡(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 Leader要具有最高的zxid
以上兩個(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í)例代碼如下所示: /** 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 |
|
來(lái)自: 風(fēng)自向前 > 《分布式》