網絡分區帶給分布式數據庫的難題如何解決?

發表于:2013-09-10來源:51CTO作者:麥子邁點擊數: 標簽:網絡分區
網絡分區帶給分布式數據庫的難題如何解決? 在OpenStack中,數據庫是主要系統“狀態”的主要來源。大部分Core Projects都使用傳統關系型數據庫作為系統數據和狀態的存儲,另外如Ceilometer使用了MongoDB,

  在OpenStack中,數據庫是主要系統“狀態”的主要來源。大部分Core Projects都使用傳統關系型數據庫作為系統數據和狀態的存儲,另外如Ceilometer使用了MongoDB,還有其他Incubator Projects使用了Redis作為隊列或者狀態存儲。數據庫給OpenStack提供了狀態組件并把狀態的“共享”問題交給了數據庫,因此解決 OpenStack的擴展問題實際上就是解決使用的數據庫本身的擴展問題。比如OpenStack HA Solution最令人頭疼的就是傳統關系數據庫或者其他數據存儲的擴展問題,數據庫擴展問題的根源是其本身不支持分布式和良好的擴展性,而這個根源又會衍生出分布式系統最大的噩夢–“網絡分區”。

  下面會分析”網絡分區“給數據庫擴展帶來的問題,同時在OpenStack組件中如何規避和解決。

  一致性

  現代軟件系統由一系列“組件”通過異步、不可靠的網絡相互溝通構建。理解一個可信賴的分布式系統需要對網絡本身的分析,而“狀態”共享就是一個最重要的問題。

  舉一個例子,當你發表一篇博文后,你可能想知道在你點擊“發布”操作之后:

  1. 從現在開始會對所有人可見;

  2. 從現在開始會對你的連接可見,其他人會延遲;

  3. 你也可能暫時不可見,但是未來會可見;

  4. 現在可見或者不可見:發生錯誤

  5. …… etc

  不同的分布式系統會有對一致性和持久性相互影響的權衡和決定,比如Dynamo類系統通過NRW來指定一致性,如果N=3, W=2,R=1,你將會得到:

  1. 可能不會馬上看到更新

  2. 更新數據會在一個節點失敗后存活

  如果你像Zookeeper來寫入,那會得到一個強一致性保證:寫操作會對所有人可見,比如這個寫操作在一半以下的節點失敗后仍然能夠保證。如果你像MySQL寫入,取決于你的事物一致性級別,你的寫操作一致性會對所有人、你可見或者最終一致性。

  網絡分區

  分布式通常假設網絡是異步的,意味著網絡可能會導致任意的重復、丟失、延遲或者亂序的節點間消息傳遞。在實際中,TCP狀態機會保證節點間消息傳遞的不丟失、不重復、時序。但是,在Socket級別上,節點接發消息會阻塞,超時等等。

  檢測到網絡失敗是困難,因為我們唯一能跟得到其他節點狀態的信息就是通過網絡來得到,延遲跟網絡失敗也無從區分。這里就會產生一個基本的網絡分區問題:高延遲可以考慮作為失敗。當分區產生后,我們沒有渠道去了解到其他節點到底發生了什么事: 它們是否還存活?或者已經crash?是否有收到消息?是否正在嘗試回應。當網絡最終恢復后,我們需要重新建立連接然后嘗試解決在不一致狀態時的不一致。

  很多系統在解決分區時會進入一個特殊的降級操作模式。CAP理論也告訴我們妖么得到一致性要么高可用性,但是很少有數據庫系統能夠達到CAP理論的極限,多數只是丟失數據。

  接下來的內容會介紹一些分布式系統是如何在網絡失敗后進行相關行為。

  傳統數據庫與2PC

  傳統的SQL數據庫如MySQL、Postgresql都提供一系列不同的一致性級別,然后通常都只能向一個primary寫入,我們可以把這些數據庫認為是CP系統(CAP理論),如果分區發生,整個系統會不可用(因為ACID)。

  那么傳統數據庫是不是真的是強一致性?它們都是使用2PC策略來提交請求:

  1. 客戶端commit

  2. 服務器端寫操作然后回應

  3. 客戶端收到回應完成提交

png;base649362479ed5433924

  在這三個步驟中,可能發生不一致的情況在于2與3之間,當服務器寫操作完成但是回應沒有被客戶端收到,無論是超時或者網絡故障,客戶端這時會認為這次操作沒有完成,而事實上數據庫已經寫入。這時就會產生不一致的行為。也就是客戶端得到的錯誤并不能解釋到底服務器端有沒有寫入。

  2PC不僅在傳統SQL數據庫被廣泛使用,也有大量用戶實現2PC在MongoDB之上來完成多鍵值事務操作。

  那么如何解決這個問題?首先必須接受這個問題,因為網絡失敗地概率比較低,并且正好在服務器寫操作完成與客戶端得到回應之間失敗。這使得受到影響的操作非常稀有,在大部分業務中,這個失敗是可接受到。相對的,如果你必須要強一致性的實施,那么應該在業務中付諸行動,比如所有的事務寫操作都是冪等的,是可重入的。這樣當遇到網絡問題時,retry即可而不管到底寫操作有沒有完成。最后,一些數據庫可以得到事務ID,通過track事務ID你可以在網絡故障后重新評估事務是否完成,通過數據庫在網絡恢復后檢查其記錄的事物ID然后回滾相應事務。

  我們在OpenStack的選擇就很有限,目前各個項目中并不是所有寫操作都是冪等的,不過幸運的是,OpenStack的數據在罕見的2PC協議特例中損失是能接受的。

  Redis

  Redis通常被視為一個共享的heap,因為它容易理解的一致性模型,很多用戶把Redis作為消息隊列、鎖服務或者主要數據庫。Redis在一個server上運行實例視為CP系統(CAP理論),因此一致性是它的主要目的。

png;base64f63e2b67b8a23c15

  Redis集群通常是主備,primary node負責寫入和讀取,而slave node只是用來備份。當primary node失敗時,slave node有機會被提升為primary node。但是因為primary node和slave node之間是異步傳輸,因此slave node被提升為primary node后會導致0~N秒的數據丟失。此時Redis的一致性已經被打破,Redis這個模式的集群不是一個CP系統!

  Redis有一個官方組件叫Sentinel(參考Redis Sentinel,它是通過類似Quorum的方式來連接Sentinel instance,然后檢測Redis集群的狀態,對故障的primary節點試用slave節點替換。Redis官方號稱這個是HA solution,通過Redis Sentinel來構建一個CP系統。

原文轉自:http://os.51cto.com/art/201307/403298.htm

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97