一、cap
分布式領(lǐng)域中存在CAP理論,且該理論已被證明:任何分布式系統(tǒng)只可同時滿足兩點,無法三者兼顧。
?、貱:Consistency,一致性,數(shù)據(jù)一致更新,所有數(shù)據(jù)變動都是同步的。
?、贏:Availability,可用性,系統(tǒng)具有好的響應(yīng)性能。
?、跴:Partition tolerance,分區(qū)容錯性。
因此,將精力浪費在思考如何設(shè)計能滿足三者的完美系統(tǒng)上是愚鈍的,應(yīng)該根據(jù)應(yīng)用場景進行適當取舍。
(1)一致性
一致性是指從系統(tǒng)外部讀取系統(tǒng)內(nèi)部的數(shù)據(jù)時,在一定約束條件下相同,即數(shù)據(jù)變動在系統(tǒng)內(nèi)部各節(jié)點應(yīng)該是同步的。根據(jù)一致性的強弱程度不同,可以將一致性級別分為如下幾種:
?、購娨恢滦裕╯trong consistency)。任何時刻,任何用戶都能讀取到最近一次成功更新的數(shù)據(jù)。
②單調(diào)一致性(monotonic consistency)。任何時刻,任何用戶一旦讀到某個數(shù)據(jù)在某次更新后的值,那么就不會再讀到比這個值更舊的值。也就是說,可 獲取的數(shù)據(jù)順序必是單調(diào)遞增的。
?、蹠捯恢滦裕╯ession consistency)。任何用戶在某次會話中,一旦讀到某個數(shù)據(jù)在某次更新后的值,那么在本次會話中就不會再讀到比這值更舊的值 會話一致性是在單調(diào)一致性的基礎(chǔ)上進一步放松約束,只保證單個用戶單個會話內(nèi)的單調(diào)性,在不同用戶或同一用戶不同會話間則沒有保障。示例case:php的 session概念。
?、?最終一致性(eventual consistency)。用戶只能讀到某次更新后的值,但系統(tǒng)保證數(shù)據(jù)將最終達到完全一致的狀態(tài),只是所需時間不能保障。
⑥弱一致性(weak consistency)。用戶無法在確定時間內(nèi)讀到最新更新的值。
很多文章和博客里提到,zookeeper是一種提供強一致性的服務(wù),在分區(qū)容錯性和可用性上做了一定折中,這和CAP理論是吻合的。但實際上zookeeper提供的只是單調(diào)一致性。
原因:
1. 假設(shè)有2n+1個server,在同步流程中,leader向follower同步數(shù)據(jù),當同步完成的follower數(shù)量大于 n+1時同步流程結(jié)束,系統(tǒng)可接受client的連接請求。如果client連接的并非同步完成的follower,那么得到的并非最新數(shù)據(jù),但可以保證單調(diào)性。
2. follower接收寫請求后,轉(zhuǎn)發(fā)給leader處理;leader完成兩階段提交的機制。向所有server發(fā)起提案,當提案獲得超過半數(shù)(n+1)的server認同后,將對整個集群進行同步,超過半數(shù)(n+1)的server同步完成后,該寫請求完成。如果client連接的并非同步完成follower,那么得到的并非最新數(shù)據(jù),但可以保證單調(diào)性。
用分布式系統(tǒng)的CAP原則來分析Zookeeper:
(1)C: Zookeeper保證了最終一致性,在十幾秒可以Sync到各個節(jié)點.
(2)A: Zookeeper保證了可用性,數(shù)據(jù)總是可用的,沒有鎖.并且有一大半的節(jié)點所擁有的數(shù)據(jù)是最新的,實時的. 如果想保證取得是數(shù)據(jù)一定是最新的,需要手工調(diào)用Sync()
(2)P: 有2點需要分析的.
① 節(jié)點多了會導(dǎo)致寫數(shù)據(jù)延時非常大,因為需要多個節(jié)點同步.
② 節(jié)點多了Leader選舉非常耗時, 就會放大網(wǎng)絡(luò)的問題. 可以通過引入 observer節(jié)點緩解這個問題.
1
2
3
1、在Eureka平臺中,如果某臺服務(wù)器宕機,Eureka不會有類似于ZooKeeper的選舉leader的過程;客戶端請求會自動切換到新的Eureka節(jié)點;當宕機的服務(wù)器重新恢復(fù)后,Eureka會再次將其納入到服務(wù)器集群管理之中;而對于它來說,所有要做的無非是同步一些新的服務(wù)注冊信息而已。所以,再也不用擔心有“掉隊”的服務(wù)器恢復(fù)以后,會從Eureka服務(wù)器集群中剔除出去的風(fēng)險了。Eureka甚至被設(shè)計用來應(yīng)付范圍更廣的網(wǎng)絡(luò)分割故障,并實現(xiàn)“0”宕機維護需求。(多個zookeeper之間網(wǎng)絡(luò)出現(xiàn)問題,造成出現(xiàn)多個leader,發(fā)生腦裂)當網(wǎng)絡(luò)分割故障發(fā)生時,每個Eureka節(jié)點,會持續(xù)的對外提供服務(wù)(注:ZooKeeper不會):接收新的服務(wù)注冊同時將它們提供給下游的服務(wù)發(fā)現(xiàn)請求。這樣一來,就可以實現(xiàn)在同一個子網(wǎng)中(same side of partition),新發(fā)布的服務(wù)仍然可以被發(fā)現(xiàn)與訪問。
2、正常配置下,Eureka內(nèi)置了心跳服務(wù),用于淘汰一些“瀕死”的服務(wù)器;如果在Eureka中注冊的服務(wù),它的“心跳”變得遲緩時,Eureka會將其整個剔除出管理范圍(這點有點像ZooKeeper的做法)。這是個很好的功能,但是當網(wǎng)絡(luò)分割故障發(fā)生時,這也是非常危險的;因為,那些因為網(wǎng)絡(luò)問題(注:心跳慢被剔除了)而被剔除出去的服務(wù)器本身是很”健康“的,只是因為網(wǎng)絡(luò)分割故障把Eureka集群分割成了獨立的子網(wǎng)而不能互訪而已。 幸運的是,Netflix考慮到了這個缺陷。如果Eureka服務(wù)節(jié)點在短時間里丟失了大量的心跳連接(注:可能發(fā)生了網(wǎng)絡(luò)故障),那么這個Eureka節(jié)點會進入”自我保護模式“,同時保留那些“心跳死亡“的服務(wù)注冊信息不過期。此時,這個Eureka節(jié)點對于新的服務(wù)還能提供注冊服務(wù),對于”死亡“的仍然保留,以防還有客戶端向其發(fā)起請求。當網(wǎng)絡(luò)故障恢復(fù)后,這個Eureka節(jié)點會退出”自我保護模式“。所以Eureka的哲學(xué)是,同時保留”好數(shù)據(jù)“與”壞數(shù)據(jù)“總比丟掉任何”好數(shù)據(jù)“要更好,所以這種模式在實踐中非常有效。
3、Eureka還有客戶端緩存功能(注:Eureka分為客戶端程序與服務(wù)器端程序兩個部分,客戶端程序負責(zé)向外提供注冊與發(fā)現(xiàn)服務(wù)接口)。所以即便Eureka集群中所有節(jié)點都失效,或者發(fā)生網(wǎng)絡(luò)分割故障導(dǎo)致客戶端不能訪問任何一臺Eureka服務(wù)器;Eureka服務(wù)的消費者仍然可以通過Eureka客戶端緩存來獲取現(xiàn)有的服務(wù)注冊信息。甚至最極端的環(huán)境下,所有正常的Eureka節(jié)點都不對請求產(chǎn)生相應(yīng),也沒有更好的服務(wù)器解決方案來解決這種問題 時;得益于Eureka的客戶端緩存技術(shù),消費者服務(wù)仍然可以通過Eureka客戶端查詢與獲取注冊服務(wù)信息,這點很重要。
4、Eureka的構(gòu)架保證了它能夠成為Service發(fā)現(xiàn)服務(wù)。它相對與ZooKeeper來說剔除了Leader節(jié)點的選取或者事務(wù)日志機制,這樣做有利于減少使用者維護的難度也保證了Eureka的在運行時的健壯性。而且Eureka就是為發(fā)現(xiàn)服務(wù)所設(shè)計的,它有獨立的客戶端程序庫,同時提供心跳服務(wù)、服務(wù)健康監(jiān)測、自動發(fā)布服務(wù)與自動刷新緩存的功能。但是,如果使用ZooKeeper你必須自己來實現(xiàn)這些功能。Eureka的所有庫都是開源的,所有人都能看到與使用這些源代碼,這比那些只有一兩個人能看或者維護的客戶端庫要好。
5、維護Eureka服務(wù)器也非常的簡單,比如,切換一個節(jié)點只需要在現(xiàn)有EIP下移除一個現(xiàn)有的節(jié)點然后添加一個新的就行。Eureka提供了一個web-based的圖形化的運維界面,在這個界面中可以查看Eureka所管理的注冊服務(wù)的運行狀態(tài)信息:是否健康,運行日志等。Eureka甚至提供了Restful-API接口,方便第三方程序集成Eureka的功能。
在分布式系統(tǒng)領(lǐng)域有個著名的CAP定理(C-數(shù)據(jù)一致性;A-服務(wù)可用性;P-服務(wù)對網(wǎng)絡(luò)分區(qū)故障的容錯性,這三個特性在任何分布式系統(tǒng)中不能同時滿足,最多同時滿足兩個);ZooKeeper是個CP的,即任何時刻對ZooKeeper的訪問請求能得到一致的數(shù)據(jù)結(jié)果,同時系統(tǒng)對網(wǎng)絡(luò)分割具備容錯性;但是它不能保證每次服務(wù)請求的可用性(注:也就是在極端環(huán)境下,ZooKeeper可能會丟棄一些請求,消費者程序需要重新請求才能獲得結(jié)果)。但是別忘了,ZooKeeper是分布式協(xié)調(diào)服務(wù),它的職責(zé)是保證數(shù)據(jù)(注:配置數(shù)據(jù),狀態(tài)數(shù)據(jù))在其管轄下的所有服務(wù)之間保持同步、一致;所以就不難理解為什么ZooKeeper被設(shè)計成CP而不是AP特性的了,如果是AP的,那么將會帶來恐怖的后果(注:ZooKeeper就像交叉路口的信號燈一樣,你能想象在交通要道突然信號燈失靈的情況嗎?)。而且,作為ZooKeeper的核心實現(xiàn)算法Zab,就是解決了分布式系統(tǒng)下數(shù)據(jù)如何在多個服務(wù)之間保持同步問題的。
1、對于Service發(fā)現(xiàn)服務(wù)來說就算是返回了包含不實的信息的結(jié)果也比什么都不返回要好;再者,對于Service發(fā)現(xiàn)服務(wù)而言,寧可返回某服務(wù)5分鐘之前在哪幾個服務(wù)器上可用的信息,也不能因為暫時的網(wǎng)絡(luò)故障而找不到可用的服務(wù)器,而不返回任何結(jié)果。所以說,用ZooKeeper來做Service發(fā)現(xiàn)服務(wù)是肯定錯誤的,如果你這么用就慘了!
如果被用作Service發(fā)現(xiàn)服務(wù),ZooKeeper本身并沒有正確的處理網(wǎng)絡(luò)分割的問題;而在云端,網(wǎng)絡(luò)分割問題跟其他類型的故障一樣的確會發(fā)生;所以最好提前對這個問題做好100%的準備。就像Jepsen在ZooKeeper網(wǎng)站上發(fā)布的博客中所說:在ZooKeeper中,如果在同一個網(wǎng)絡(luò)分區(qū)(partition)的節(jié)點數(shù)(nodes)數(shù)達不到ZooKeeper選取Leader節(jié)點的“法定人數(shù)”時,它們就會從ZooKeeper中斷開,當然同時也就不能提供Service發(fā)現(xiàn)服務(wù)了。
2、ZooKeeper下所有節(jié)點不可能保證任何時候都能緩存所有的服務(wù)注冊信息。如果ZooKeeper下所有節(jié)點都斷開了,或者集群中出現(xiàn)了網(wǎng)絡(luò)分割的故障(注:由于交換機故障導(dǎo)致交換機底下的子網(wǎng)間不能互訪);那么ZooKeeper會將它們都從自己管理范圍中剔除出去,外界就不能訪問到這些節(jié)點了,即便這些節(jié)點本身是“健康”的,可以正常提供服務(wù)的;所以導(dǎo)致到達這些節(jié)點的服務(wù)請求被丟失了。(注:這也是為什么ZooKeeper不滿足CAP中A的原因)
3、更深層次的原因是,ZooKeeper是按照CP原則構(gòu)建的,也就是說它能保證每個節(jié)點的數(shù)據(jù)保持一致,而為ZooKeeper加上緩存的做法的目的是為了讓ZooKeeper變得更加可靠(available);但是,ZooKeeper設(shè)計的本意是保持節(jié)點的數(shù)據(jù)一致,也就是CP。所以,這樣一來,你可能既得不到一個數(shù)據(jù)一致的(CP)也得不到一個高可用的(AP)的Service發(fā)現(xiàn)服務(wù)了;因為,這相當于你在一個已有的CP系統(tǒng)上強制栓了一個AP的系統(tǒng),這在本質(zhì)上就行不通的!一個Service發(fā)現(xiàn)服務(wù)應(yīng)該從一開始就被設(shè)計成高可用的才行!
4、如果拋開CAP原理不管,正確的設(shè)置與維護ZooKeeper服務(wù)就非常的困難;錯誤會經(jīng)常發(fā)生,導(dǎo)致很多工程被建立只是為了減輕維護ZooKeeper的難度。這些錯誤不僅存在與客戶端而且還存在于ZooKeeper服務(wù)器本身。Knewton平臺很多故障就是由于ZooKeeper使用不當而導(dǎo)致的。那些看似簡單的操作,如:正確的重建觀察者(reestablishing watcher)、客戶端Session與異常的處理與在ZK窗口中管理內(nèi)存都是非常容易導(dǎo)致ZooKeeper出錯的。同時,我們確實也遇到過ZooKeeper的一些經(jīng)典bug:ZooKeeper-1159 與ZooKeeper-1576;我們甚至在生產(chǎn)環(huán)境中遇到過ZooKeeper選舉Leader節(jié)點失敗的情況。這些問題之所以會出現(xiàn),在于ZooKeeper需要管理與保障所管轄服務(wù)群的Session與網(wǎng)絡(luò)連接資源(注:這些資源的管理在分布式系統(tǒng)環(huán)境下是極其困難的);但是它不負責(zé)管理服務(wù)的發(fā)現(xiàn),所以使用ZooKeeper當Service發(fā)現(xiàn)服務(wù)得不償失。