考慮Redis Sentinel在網絡分區時候的情況,這時Redis集群被網絡分成兩部分,Redis Sentinel在的大區域可能會提升Slave node作為primary node。如果這時候一直client在連接原來的primary node,這時會出現兩個primary node(split-brain problem,腦裂問題)!也就是說,Redis Sentinel并沒有阻止client連接Old primary node。在此時,已經連接到old primary node的client會寫入old primary node,新的client會寫入到new primary node。此時,CP系統已經完全癱瘓。雖然Redis集群一直是保持運行的,但是因為依賴于Quorum來提升slave節點,因此它也不會是AP系統。
如果使用Redis作為Lock service,那么這個問題會成為致命問題。這會導致分區后同時可以有兩個client獲取同一個鎖并成功,lock service必須是嚴格的CP系統,像Zookeeper。
如果使用Redis作為queue,那么你需要接受一個item可能會被分發零次、一次或者兩次等等,大部分的分布式隊列都保證最多只分發一次或者最少分發一次,CP系統會提確切一次的分發然后帶來較高的延遲。你需要明確使用Redis作為隊列服務的話必須要接受網絡分區后隊列服務可能導致的不穩定。
如果使用Redis作為database,那么可想而知,利用Redis Sentinel建立的database是不能稱為database的。
最后,以目前的Redis來說,使用官方提供的組件它只能成為Cache。構建一個分布式的Redis前往WheatRedis。
MongoDB
MongoDB采用類似于Redis的集群方式,primary node作為單點寫操作服務然后異步寫入replication nodes。但是MongoDB內建了primary選舉和復制狀態機,這使得primary node失敗后,整個MongoDB會進行交流然后選擇一個合適的slave node。然后MongoDB支持指定primary node可以確認slave node已經把寫操作寫入log或者真正寫入,也就是通過一定的性能損耗來換取更強的一致性當primary node失敗后。
那么MongoDB是否可以認定為是一個嚴格的CP系統?還是與Redis類似的問題,在網絡分區后,當primary node在小的分區里,大的分區里的node會選舉產生一個新的primary node,而此時在分區的時候,這兩個node是會同時存在的(這個沒有問題),然后當分區恢復后,小分區里的old primarynode會把在腦裂期間的操作發送到new primary node,這時候可能會產生沖突!
那么如何面對這個問題?接受它,首先這個沖突的概念像2PC一樣可以在client端解決,同時MongoDB目前有WriteConnern可以解決這個問題,但會造成巨大的性能影響。
Dynamo
Dynamo是在傳統的primary-slave模式遇到問題時候出現的紅寶書,借鑒Dynamo的產品在一段時間內出現的非常多。
之前提到的系統都是面向CP的,起碼是面向CP設計的。Amazon設計的Dynamo鮮明地面向AP。在Dynamo,它是天然地分區友好型,每一個node都是平等的,通過NWR來指定不同地一致性級別和可用性。這里不會詳細闡述Dynaomo的原理(Dynamo,每一個試圖了解分布式系統的人都應該對Dynamo這篇論文非常熟悉,即使它面臨很多問題,但是論文中出現的對Dynamo設計的思考和變遷是寶貴的。
那么當分區發生時,Dynamo發生了什么?首先根據NWR的推薦設定(W+R>N),小區是不能得到新的寫操作,新的對象會寫在大區。然后在分區恢復后,小區的對象會滯后并與新的對象發生沖突。這里的沖突解決策略非常多,如Cassandra使用的client timestamps,Riak的Vector clock,如果無法解決,沖突可能會硬性覆蓋或者推到業務代碼。
然后Dynamo本身沒有任何方法來判斷一個節點是否數據同步,也無法判斷,只能通過完全的數據比較,而這個過程是代價昂貴并且不靈活的。因此Dynamo提到說(W+R>N)可以達到強一致性是不可能的,故障節點只會是最終一致性。
因此,解決Dynamo的問題像前面一樣,接受它。首先你的數據可以設計成immutable,然后你的數據決定可以在罕見情況下丟棄或者變舊,再或者使用CRDTs來設計你的數據結構。無論如何,Dynamo始終是一個good idea并且它推動了分布式設計的發展。
BigTable
上面提到的系統都是面向分布式的,要么AP要么CP。那么Bigtable是AC系統,雖然我們介紹的一直是分區問題,但是我們也需要考慮在中心化設計的Bigtable。無論是HBase還是HDFS都是這類設計,它們回避了分區問題并且在單IDC下達到非常好的效果。這里不會詳細討論中心化設計,因為它根本就沒有考慮分區問題。
分布式數據庫系統的思考
通過上述的分析可以了解到構建一個分布式數據庫集群的困難,無論是同步復制,異步復制,Quorum還是其他的,在網絡分區面前,任何掙扎都是無力的,網絡錯誤意味著”I don’t know” not “I failed”。
構建一個“正確的”分布式數據庫系統通常在幾個方面達成意見: 1. 接受罕見的問題 2. 使用開源的軟件,分布式系統會產生極大的“漩渦”在“理論正確的分布式算法”和“實際使用的系統“。一個有Bug的系統但是正確的算法比一個錯誤的設計更能接受。 3. 利用問題進行正確的設計,如使用[CRDTs](http://pagesperso-systeme.lip6.fr/Marc.Shapiro /papers/RR-6956.pdf) 4. split-brain問題是分區的原罪,如何解決split-brain之后的遺產才是正確的解決方案
小結
如何在OpenStack上做到HA是OpenStack官方和其他發行版公司都在努力的方向,而其中關鍵就在于數據存儲的HA和一致性,在這個方向上,我們通過對”網絡分區“這一關鍵問題的分析并在不同類型的數據庫上進行落地思考,可以得到如何在其上規避、解決和接受它。通過在OpenStack 的產品上思考這些問題,我們可以在HA Solution上有更強健的基礎。
原文轉自:http://os.51cto.com/art/201307/403298.htm