精品国产一级在线观看,国产成人综合久久精品亚洲,免费一级欧美大片在线观看

云存儲的黑暗面:元數據保障

責任編輯:editor005

2015-08-06 15:52:54

摘自:分布式系統架構知識微信號

本文主旨并非闡述一個可用的架構設計,而是展示出對象存儲的元數據保障中將會遇到的問題。多副本模型的核心難點集中在一致性保障方面,針對這些問題都有相應的解決手段,但都無法完全消除問題的存在。

本文主旨并非闡述一個可用的架構設計,而是展示出對象存儲的元數據保障中將會遇到的問題。問題往往比答案更重要。多數問題只要認識清楚,解決并非難事。但需要注意的是,沒有哪個問題存在十全十美的徹底解決方案。我們所采取的策略更多的是將一個關鍵性問題轉化成另一個次要和易于處理的問題,或者將一個問題發生的可能性盡可能降低。很多問題是無法徹底解決的,我們的現實目標是將其發生的概率下降到業務可接受的范圍。因此,希望大家能夠更多地關注和發掘所存在的問題,而不是緊盯方案和設計。我們相信,認清了問題之后,找到解決辦法并非難事。

在開始討論元數據保障的問題之前,我們先要牢牢記住一句話:“任何事物都會出錯。”這個真理時時刻刻在發揮著驚人的作用。

元數據

元數據系統的好壞關系到整個對象存儲系統的可靠性、可用性和一致性,并且會影響到性能。因此,元數據部分是對象存儲系統的核心,也是架構和保障的重中之重。

元數據最基本的作用在于數據對象的定位。對象存儲的任務是保存用戶提交的數據對象,并以用戶指定的名稱(Key)對其標識。用戶如需獲取一個數據對象,要向對象存儲系統提交Key,存儲系統便會根據Key找到相應的數據對象,然后反饋給用戶。存儲系統根據Key找到數據對象存放位置的過程,便是依托元數據完成的。圖1是元數據方案架構圖。

云存儲的黑暗面:元數據保障

元數據的核心內容是Key=>Pos(存儲位置)的映射,本質上是一個Map。此外,元數據還承載了數據對象歸屬(容器和用戶)、大小、校驗值等元信息,用于記賬、校對、修復和分析等輔助操作。

說到這里,大家或許會有疑問:現今的存儲系統都流行去中心化,設法去掉元數據,為何還要談元數據的保障?原因其實很簡單,當今各種去中心化的存儲設計,在云存儲中并不適用。其中原因頗為繁復,已超出本文范疇,這里只做簡單說明。

去中心化的方案利用算法確定數據對象的位置。最常見的算法是一致性哈希。這些方案的問題在于,如果僅考慮數據對象的存取,邏輯很簡單,實現上也簡單。但如果考慮到可靠性、可用性、一致性,以及運維,就會變得復雜。

數據對象的存儲副本總會損壞和丟失。一旦丟失,需要盡快修復。最極端的情況是某一磁盤失效,進而造成大量的數據副本需要修復。去中心化方案將數據對象的副本同磁盤一一對應起來,結果就是修復的數據只能灌入一塊磁盤。單塊磁盤的吞吐能力有限,從而造成一塊磁盤的數據需要近一天的時間方能修復。而在大型存儲系統中,這段時間內可能會有更多的磁盤發生損壞,因而可能造成數據的丟失。

同樣因為數據對象與服務器和磁盤綁定,一旦一臺服務器下線,便會降低相應對象的存取可用性。有些方案臨時將數據對象映射到其他服務器,從而提高可用性,但臨時狀態的管理、其間的異常處理等問題的復雜性遠遠超出了去中心化所帶來的便利。

當存儲系統擴容時,去中心化方案需要在服務器之間遷移大量的數據,以求各磁盤的可用容量達到平衡。遷移規模隨擴容規模增大而增加。遷移過程消耗系統資源,并且存在中間狀態,使得數據存取邏輯復雜化。而且漫長的遷移過程中一旦發生異常,其處理過程相當繁復。

在一致性方面,去中心化方案礙于副本數較少,在某些特定情況下會造成一致性問題,而且難以修復。關于這一點,后面會具體論述。

對于list操作、數據校驗、記賬等輔助操作,各種去中心化的方案都很不友好。因為數據量龐大,無法通過遍歷所有數據計算用量、分析統計。因此,一些去中心化方案會設置數據對象和用戶的關聯數據庫,以方便使用量計算。這些數據庫實際上就是一種元數據庫,同樣面臨著元數據保障的問題。

去中心化方案的諸多問題并非無法解決,總能找到合適的方法應對。但其實這只是將壓力轉移到運維階段,使得運維成為瓶頸。我們說存儲系統是“三分研發,七分運維”,運維是重中之重,無論從設計還是研發角度,都應當以方便運維,減少運維壓力為先。表1中對比了去中心化方案和元數據方案。

元數據的特性

讓我們回到元數據上來。元數據相對于數據對象本身,總量較少。根據統計,元數據和數據對象的大小之比大體在1:100到1:10000之間,具體的比率,取決于數據對象的平均大小。因此,元數據相比數據對象本身更加容易操作和處理。

當用戶索取數據對象時,存儲系統需要檢索元數據庫,找到相應的元數據條目,獲得存儲信息后,進行讀取。因此,元數據的操作是查詢操作,也就是數據庫操作。正因為元數據的量較少,并且都是結構化數據,使得這種檢索得以方便地實現。

即便如此,當存儲量達到幾十PB級別時,元數據的數據量也將達到幾十上百TB的級別。這已遠超出單臺服務器的存儲能力。因此,元數據庫天生便是一個分布式集群。在分布式數據庫集群中,很難維持復雜的數據結構,特別是在可靠性、可用性、一致性,以及性能的約束下,同時滿足這些要求是極難做到的。在動輒數以PB計的云存儲系統中,只得維持最簡單的對象存儲形態,這也就是大型的云存儲系統不支持文件系統的原因。

元數據的重要性在于它是整個數據存儲的基準:整個系統擁有哪些數據對象,歸屬哪些容器、哪些用戶。一個數據對象,元數據說有,就有了;元數據說沒有,就沒有了。所以,元數據的可靠性代表著存儲系統的可靠性。數據校驗、空間回收等操作都依賴于元數據。元數據一旦有所差錯,必然造成整個數據存儲的錯失和混亂。

同時,幾乎所有操作都需要操作元數據,或讀取,或寫入,是存儲系統的關鍵路徑。如果元數據系統下線,那么整個存儲系統就會宕機。因此,元數據部分的可用性決定了存儲系統的可用性。

性能方面,幾乎所有的操作都涉及到元數據,整個元數據系統的訪問壓力遠遠超過存儲系統。因而,元數據的性能決定了存儲系統的整體響應。

元數據的一致性也決定了存儲系統的一致性。一致性決定了用戶在不同時間對同一個對象訪問是否得到同樣的結果。當一致性發生問題時,用戶在不同的時間可能獲得某個對象的不同版本,甚至無法獲得有效的對象。這些違背用戶預期的情況往往造成用戶業務邏輯的混亂,引發不可預期的結果。而在某些特定的情況下,一致性的錯亂會增加數據丟失的可能性。

作為存儲系統的樞紐,元數據占到整個系統大部分的維護工作量。元數據系統可維護性上的提升對于整體的運維有莫大的幫助。

元數據保障的真正困難在于上述這些特性的平衡和協調。這些特性之間有時會相互補充,但更多的時候會相互矛盾和沖突。試圖解決其中一個方面的問題,可能導致其他方面受到損害。解決問題的過程充滿了大量的折中手段。

接下來具體說一說云存儲元數據保障所面臨的問題和一般應對手段。

主從模型

首先我們必須解決可靠性和可用性問題,盡可能保證保存下來的元數據不丟失,也盡可能讓服務始終在線。這里有一個關鍵點:怎樣才算保存下來?這個問題看似簡單,實則至關重要。一般我們會認為所謂保存下來就是存儲到磁盤或其他持久存儲設備上。但在一個在線系統中無法以此界定。在一個在線服務中,數據完成保存是指明確向客戶端反饋數據已經正確保存。一旦向客戶端發出這樣的反饋,那么便是承諾數據已經保存下來。在這個界定之下,元數據的可靠性保障則頗為復雜。

前面說過,元數據系統是一個數據庫系統,保障數據庫系統可靠性最常用手段就是主從模型(圖2),即讀寫主數據庫,而主數據庫將數據復制到從數據庫,從而確保數據庫沒有單點。主從模型同時也保障了可用性,當主服務器下線時,從服務器可以切換成主服務器,繼續提供服務。這樣的保障手段對于一般的在線應用大體上夠用了,但對于云存儲的元數據而言,則存在諸多問題。其中緣由頗為復雜,讓我們從最基本的可靠性開始。

云存儲的黑暗面:元數據保障

主從模型是依靠主服務器向從服務器復制每次寫入的數據,以確保數據存留不止一份。但這里有個同步和異步的問題。所謂“異步”是指主服務器完成數據寫入之后,即刻向客戶端反饋寫入成功信息,然后在適當的時候(通常都是盡快)向從服務器復制數據。客戶端得到保存完成的信息后便歡歡喜喜做后面的事情去了。而此刻相應的數據只有主服務器上保存著,如果發生磁盤損壞之類的問題,便會丟失那些尚未來得及復制到從服務器的數據。之后如果客戶端來提取這條數據,服務端卻無法給出,對存儲系統而言,是很丟人的事。

即便沒有發生硬件損壞的情況,依然可能丟失數據。由于硬盤之類的存儲介質速度緩慢,無法跟上數據訪問的節奏,所以數據庫都會使用內存進行緩存。當服務器發生掉電或者崩潰,數據庫發生非正常的退出時,都會造成緩存中沒有寫入磁盤的數據丟失,進而造成數據的丟失。

在存儲系統長期的運行過程中,硬件肯定會壞,掉電必然會發生,系統也難保不會崩潰。所以這種異步的數據復制過程必然會有數據的丟失。這對于在線存儲服務而言是無法容忍的。

既然異步存在這樣的問題,那么同步地復制數據是否會好些呢?所謂“同步”是指主服務器完成數據寫入后,并不立即反饋用戶,而是先將數據復制到從服務器。等到從服務器正確寫入,再向用戶反饋數據寫入完成。這樣,任何時刻都會至少有兩臺服務器擁有某一條數據,即便一臺服務器出了問題,也可以確保數據還在。如果有多臺從服務器自然就萬無一失了。

同步模式解決了可靠性問題,卻引入了新問題。最基本的問題就是同步的數據復制造成延遲的增加:主服務器需要等待從服務器完成寫入才能反饋。

讓我們先放下性能問題,畢竟在線對象存儲對于主從同步的延遲還沒有那么敏感。剩下的問題則是根本性的。同步模式解決了可靠性問題,下一步需要考慮可用性問題。對于在線存儲服務而言,必須要確保系統不受單點故障的影響。同步模式則恰恰受制于此。為了確保可靠性,必須主從服務器都寫入成功,才能向用戶反饋成功。如果從服務器下線,那么這個條件就被破壞,不得不向用戶反饋失敗,直到從服務器重新恢復。而當主服務器下線后,從服務器則設法升級為主服務器繼續服務。但此時只有一臺服務器,也不能滿足數據不少于兩份的要求。如果允許主從之間容忍從服務器的下線,那么可靠性又受到了削弱。這樣產生了令人啼笑皆非的結果,主從模型是為了提高可靠性和可用性,現在反到受制于單點故障。

解決這一問題的方法也不是很難:增加從服務器的數量,并且允許主從復制失敗。如此,當一臺從服務器下線后,其他從服務器依然可以接收數據,確保任何時刻一份數據都至少擁有兩個以上的副本,以維持可靠性。不過,具體操作上并沒有那么簡單,主從之間復制成功的數量必須滿足一個閾值。這個閾值也必須滿足一個條件才能保證數據一致性,關于這個要點后面會具體闡述。

又有新的問題出現。當主服務器下線時,一臺從服務器便會被升級成為主服務器。但前面說了,為了可用性,并不要求主從服務器間的復制每次都成功,那么新的主服務器的數據可能是不完整的。這樣對于用戶而言,便會出現數據一致性的問題:原先成功寫入的數據卻讀不到了,或者讀到的都是很舊的版本,已被覆蓋掉的東西。給用戶造成的印象便是數據丟失了,這是嚴重的問題。

最直觀的解決途徑是設法補上那些數據。但考慮到元數據的量,這樣的修補是無法在短期內完成的。另一個更復雜卻真正有效的方法是讀取數據時,同時讀所有的服務器,不管主從。然后將所得的結果整合在一起,找出正確的版本。

事情還沒有完結,存放在數據庫中的數據經年累月地運行之后,會逐步退化。磁盤的失效,磁道的損壞,乃至人為的操作失誤,都可能造成數據副本的丟失。換句話說,即便是主服務器,我們也無法完全保證數據的完整性和一致性。無論如何都無法回避主從服務器之間的一致性問題。

無論是主服務器,還是從服務器,終究需要對缺失的數據副本進行修補,否則數據的退化終究會造成數據的遺失。這種修補的過程也是困難重重,后面會進一步分析。

最后,最重要的就是運維。架構、設計、開發之類的都是短期過程,雖說系統需要不斷演進,但畢竟都是階段性的工作。而運維,則是持久的、不間斷的任務。一個在線服務的正常運行最終還要依賴運維,運維決定了服務的品質。因此,一個設計方案的可維護性具有很高的優先級。

在可維護性方面,主從模型除了常規的系統維護事務外,還有很多額外的運維過程。主服務器下線,需要將某一臺從服務器切換為主服務器,這個過程是一個運維過程。理論上,一個主從集群可以實現自動切換。但實際使用中,這種切換并不能確保成功,往往需要人為干預,切換失敗也是常有的事。對于計劃中的下線,如升級軟硬件等,運維強度尚不算大,但對于軟硬件故障造成的突發下線,主從切換往往是緊急運維事件。一旦失敗,便是服務下線的大事故。其中充滿了風險和不可控因素,并不利于存儲服務的高可用。

一個在線系統的架構,最好的情況就是無論是正常運行,還是發生意外故障,都能夠以同一種方式運行,無須額外的應急處理。用通俗的話說,在線系統必須能夠不動聲色地扛住局部異常,為運維人員贏得回旋處理的余地。對于云存儲的元數據系統尤是如此。元數據位居關鍵路徑,又存在持久化的狀態,還受到各種特性要求的約束,它的架構著實是一項富于挑戰的任務。

多副本模型

下面我們考查一個模型,暫且簡單地稱其為多副本模型。因為這種模型,就是利用眾多元數據副本來保證可靠性和可用性的。與主從模型不同的是,多副本模型的各副本之間沒有主次之分,所有的副本都處于相同的地位。因而,在向多副本模型寫入元數據時,是同時向這些副本發起寫入。而讀取元數據時,也是向這些副本同時讀(圖1)。

云存儲的黑暗面:元數據保障

  圖1 多副本模型

多副本模型基于這樣一個簡單而直觀的思路:單點會造成數據丟失,并引發可用性問題,那么就將數據同時寫入多個服務器,以防單點的出現。不同于主從模型中,讀寫都針對一臺主服務器,從服務器只是間接地參與可靠性和可用性的保障,多副本模型的每臺服務器任何時刻都在直接發揮著保障作用。

由于每次讀寫都施加在所有的副本服務器上,任何時刻都有不止一份數據被保存下來,所以可靠性自然就解決了。同樣,任何時刻都有不止一臺服務器在運行,它們同時下線的可能性極小(暫且不考慮機房級別的整體故障),所以可用性也無需額外措施,便可以得到保障。正是因為每臺副本服務器都是平等的,所以任何一臺服務器下線都不會對整個集群的可用性和可靠性產生影響,系統仍然依照正常情況下的方式運行,別無二致。

這是多副本模型相對于主從模型的最大優勢。無論哪臺服務器下線,都不會引起系統運行狀態的變化,運維人員可以從容地進行善后處理,沒有服務下線的顧慮。而軟硬件升級之類的日常維護工作,也不需要大動干戈地進行主從切換之類的危險操作,直接將服務器下線,進行更新便可。多副本模型的系統甚至可以容忍多臺服務器下線,而不會造成系統運行的波動。具體的容忍限度取決于配置設定,關于這一點,后文有詳細論述。

任何事物都有兩面,既然多副本模型有它的優點,自然也有缺點。多副本的問題主要在一致性方面。由于我們允許副本服務器寫入失敗,再加上各種原因造成的數據退化,所以副本服務器之間的數據會不一樣。當我們讀取的時候以哪個為準呢?

這是一個值得考慮的問題。我們無法確定哪臺副本服務器包含了完整新鮮的數據。實際上不可能有這樣的服務器存在。因而我們也就無法從任何一臺服務器中準確無誤地讀出所需的數據。唯一的辦法就是同時讀所有的副本服務器,綜合所得的副本數據,以獲得所需的信息。

如何綜合副本數據呢?首先要確定基準。基準就是判定有效數據的標準,有時間基準和空間基準之分。時間基準用來處理元數據的先后覆蓋,而空間基準用于處理副本之間的對應關系。在描述如何確定基準之前,先定下這樣一個準則:對于一個數據對象的元數據,只有時間最近的那條是有效的。有了這樣的準則,建立基準就容易了。我們可以為每一次元數據寫入加上一個時間戳,并且確保一次元數據寫入的各個副本擁有相同的時間戳,同時還需保證歷次寫入的元數據擁有不同的時間戳。只要能確保這兩個條件,數據的基準就容易確立了。

具體的方法并不復雜,將讀取到的副本數據放在一起比對,時間戳上最近的那些副本,就是所需要的。但并非所有的最大時間戳都是有效的。假設這樣一種情況:一個元數據系統有5個副本,一次寫入時,由于種種原因,只有兩個副本寫成功了。在讀取這條元數據時,恰好那兩臺寫成功的副本服務器下了線。這種情況下,這條元數據就無法讀到了。其結果就是元數據不見了,直到那兩臺服務器重新上線。

為了避免這種情況的出現,我們需要引入一個規則,以確保無論怎樣都能讀到正確的數據。

這樣的方法有不少,最常用的是WRN算法(圖2)。這種算法比較簡單,容易實現,使用也較廣。算法的具體操作如下。

圖2 WRN算法

假設有N個副本,當需要訪問數據時,同時寫或者讀所有副本。如果寫入時,有超過W個副本寫成功,那么就認為這次寫入是成功的,否則就算失敗,向客戶端反饋寫入失敗。讀取時也一樣,如果有超過R個副本讀取成功,就認為這次讀取是成功的,否則就算失敗,或者數據不存在(具體是失敗,還是不存在,需根據副本讀取的結果加以判別)。W和R必須滿足一個條件:W+R>N。只要滿足這個條件,成功寫和成功讀的副本之間必然存在重疊,因而肯定可以讀到至少一個有效的數據。

在具體使用中,WRN算法還有不少需要注意的細節。首先,具體讀取各副本時,最簡單的策略是取得該副本服務器中最新的那條元數據,然后依靠WRN算法整合這些所得的數據。這種做法在一般情況下可以正常工作,但在一些異常情況中會存在一致性問題。一種情況是一次寫入時,沒有滿足成功寫入W份副本的條件,那么這次寫入算作失敗。但其中寫成功的副本因為時間戳更近,讀取該副本時,會覆蓋先前成功寫入的那些副本。于是,最新寫入失敗的那個元數據讀取時沒有達到足夠數量,而先前成功寫入的元數據因為某些副本被這次失敗的殘留副本遮蓋,也無法達到R數。于是便會出現無法取得有效元數據的情況。

這種情況屬于低概率事件,但云存儲系統經年累月不間斷地運行,任何低概率的事件都會發生,而且必然發生。一旦發生,便會引發數據錯亂的情況,影響用戶的使用和服務的聲譽。

針對這樣的問題,有一些解決手段。最基本的手段是對于失敗的寫入操作,將各副本進行回滾。也就是將那些已成功寫入的元數據條目副本刪除。這種做法可以在一定程度上有效地降低問題發生的概率。但基于“任何東西都會出錯”這樣一個事實,我們認為回滾也會失敗。回滾失敗意味著依然會發生元數據無效的問題。

另外,還有一個解決方法:讀取副本時不是只讀最近的那一條元數據,而是讀出幾條。把各副本讀到的元數據根據時間戳相互對位,還原出最原始的寫入狀態。在此基礎上,剔除那些失敗的寫入數據,得到正確的數據。

還原寫入歷史的操作要求元數據在數據庫中采用只增的方式,以便保留歷史的條目。每次元數據的寫訪問,無論是新增還是覆蓋,都是增加一條記錄。與原有的元數據記錄不同的是,這條記錄攜帶新的時間戳。對于刪除操作,則同樣增加一條數據,并且設置記錄中的“刪除”標志,系統將根據此標志判斷記錄的刪除操作。(只增也有助于避免事務,減少數據庫鎖的使用,對提升性能有所幫助。)

但與任何一種問題解決手段一樣,這種還原歷史操作的方法也不能徹底消除一致性的問題,原因是數據退化。假設一次寫入正好成功了W個副本,那么這次寫入盡管成功了,但仍處于臨界狀態。如果有一個原先成功的副本發生了丟失,那么之后這次寫入將會被認為是失敗的,而被忽略。盡管這是更加鮮有的情況,但確實會發生,而且無法直接消除。一般情況下,我們也只能容忍這種情況的存在,畢竟發生的概率已經非常非常小了。

一些輔助手段可以進一步減少這類問題發生的可能性。如果一次寫入的成功數超過了W,但依舊有少量失敗,那么要實時地對這些失敗寫入進行修復,例如重試,或者使用異步的重試隊列對失敗進行修復。這種手段和失敗回滾一起可以很有效地減少容易產生混淆的臨界狀態的存在。

失敗修復和回滾之類的錯誤處理手段實際上并非很多人認為的那么有效,錯誤處理本身也會失敗。如果試圖以錯誤處理消除問題的隱患,那么必須也要對錯誤處理的失敗情況加以處理。于是,就會有錯誤處理的錯誤處理,錯誤處理的錯誤處理的錯誤處理……如此便無窮無盡,這自然不是解決問題之道。錯誤處理的作用是減小問題發生的概率,最終將其減小到一個可以接受的范圍。

但考慮到數據退化,僅有簡單的修復是不夠的。一則錯誤處理不可能永遠成功,二則并非每一次數據丟失都會被感知。我們需要一個最終的一致性修復手段,這個手段可以彌補其他異常處理失敗造成的問題。但這樣的手段也會失敗,為了能夠最終確保錯誤得到修復,這種手段的失敗處理方式就是它自己。一般情況下,最終手段不需要有很強的實時性要求,它的任務在于應對那些概率很低的情況。在對象存儲系統中,這個手段就是定期合成元數據快照。

元數據快照的做法是這樣的:定期導出所有副本的元數據,按照時間戳匹配各條元數據,然后依照WRN算法逐條將所有副本整合,拋棄那些失敗的殘留數據,剔除被覆蓋的元數據。最終生成一個完整一致的快照。然后再重新載入元數據庫,替換快照所涵蓋的數據。

快照生成的主要問題是時間。元數據的量為數不少,通常都會在TB級別之上。對這樣的數據規模進行匹配和計算,往往需要在一個集群中以Map-Reduce處理。考慮到成本,這樣的集群規模不可能很大,因而處理的時間將會比較長,可能達數小時。而且,數據的導出和加載也需要較長的時間。同時,作為一個定期的運維過程,如何自動化,減少人力參與也是非常重要的。總體上,如何快速并且自動地合成快照是頗有挑戰的任務。

快照還有一些額外的作用,包括:生成每個容器的數據量、對象數等統計信息;生成每塊硬盤的對象清單,用于磁盤失效后的數據恢復和數據對象的校對。

快照的生成周期通常設置在一天。那么一條元數據的不一致情況最多只會存在一天,一天之后,該條元數據的所有副本又會恢復到一致的狀態。而只要一天內沒有發生多臺服務器同時丟失數據的情況,元數據的可靠性便可以得到很好的保障。我們相信一天內2臺以上服務器發生數據丟失的可能性極小。反倒是人為的操作失誤更容易造成這類事故。而這就是另一個問題了,不在本文的討論范圍內。

除了上述這些奇妙問題之外,還有一個在WRN理論中沒有被提及的問題。多數涉及WRN的論文都說這個算法可以保證強一致性,但實際上這是錯的。WRN算法如果要保證強一致性需要有一個條件,就是對每一個副本的寫入要么成功,要么失敗。在實際的使用過程中,副本的寫入卻有第三種狀態。

對于一個副本的寫入必然是跨越網絡的。于是,一次副本寫入實際包含三個步驟:向副本服務器發送請求;副本服務器寫入數據庫;反饋寫入的結果。如果前兩個步驟發生錯誤,那么這次副本寫入操作就是完完全全的失敗。但如果前兩個步驟都成功了,但第三個步驟出現了問題,如網絡連接中斷,或者數據報文丟失等,客戶端會認為這次操作是失敗的。但實際上這條數據已正確地寫入了數據庫。如果此時反饋信息恰巧達不到W數,那么就會回復用戶這次元數據寫入失敗。而實際數據庫中,成功寫入的副本數卻是滿足W數的。在下一次讀取這個元數據時,卻讀到了被認為失敗的元數據。也就是說,外界認為一個不存在的元數據,在系統中卻是真實存在的。這種一致性問題同樣是無法消除的。失敗回滾操作可以減少問題的發生概率,但終究無法徹底杜絕。

整體上,多副本模型輕而易舉地解決了可靠性和可用性,卻將問題集中到一致性上。一致性問題有很多既定的解決手段,每一種手段都有各自的問題,無法徹底將一致性問題解決。但綜合這些手段,可以很好地將一致性提升到近似的強一致性級別,從而滿足實際的需要。

WRN算法在具體使用中,N、W、R的選擇頗有些講究。首先,N數不能太少。我們來看幾種不同的WRN設置:

N=3,W=2,R=2,W+R-N=1

N=6,W=4,R=4,W+R-N=2

N=9,W=6,R=6,W+R-N=3

這三種配置都滿足W+R>N。但效果卻完全不同。對于N=3的配置,只能容忍1臺服務器下線。另外一個更麻煩的問題是,盡管寫入時有兩個副本成功了,一個副本失敗,這算是成功的。但如果其中一個成功寫入的副本發生了丟失,這時候殘存的只有一個副本,那么我們在讀取時,實際上無法判別這一個副本是寫入失敗殘存的副本,還是副本退化造成的。N=3時,這種混淆很容易發生。

而隨著N數的增大,所能夠容忍的副本下線和副本退化的數量就多了。在既定時間段內,同時下線多個副本,或者同時丟失多個副本的概率就小很多了。因此,從一致性保障角度而言,N數越大越好。當然,考慮到資源,N數終究不可能無限多,一般6-9是比較容易接受的數字。盡管副本數如此多,但畢竟元數據相對數據存儲本身有著多個數量級的差異,所占用的服務器資源畢竟還是少數。

在這里,我們可以看到那些去中心化方案在一致性保障方面的缺陷:因為數據本身的量較大,所以考慮到成本,副本數不會太多,通常會選擇N=3。很明顯,3這個數字對于一致性保障而言還是相當脆弱的。

至于W和R的具體數值,一般沒有太多的教條,但它們受制于存儲系統的部署。通常,對于云存儲系統而言,為了保障盡可能高的可靠性和可用性,會設法將存儲集群按照副本分散到不同的子集群中。每個子集群擁有獨立的交換機、獨立的配電線路,最好在物理位置上也相互獨立。最極端的情況就是分布在不同的IDC中(當然不是所有的云計算服務商都有這樣的資源)。這樣的子集群通常稱為zone。設置這樣的zone的目的是為了消除在基礎設施上的單點故障。

在這樣的部署結構下,W和R的選擇應當確保在一個zone里的副本服務器數量不大于W+R-N。這樣的設置,是為了保證一個zone下線后,系統依然有足夠的副本服務器滿足WRN算法。

主從模型vs.多副本模型

從前面關于主從模型和多副本模型的介紹可以看到兩者的差異。主從模型中,主服務器必然會由于各種原因而下線。一旦主服務器下線,那么就必須即刻采取行動,將從服務器切換成主服務器,保證系統依舊在線。但這種切換操作同樣也會失敗,而且失敗的可能性并不小。

多副本模型更易于保障可靠性和可用性。在多副本模型下,一個成功寫入的元數據任何時刻都會有多個副本存在,任何時刻都會有多個實例在提供服務。服務器單點故障不會對元數據系統的運行產生影響,整個系統還是按照正常的運作方式運行。這一點非常重要,這意味著可以將一個實時的在線運維事件變成了可以暫緩處理的離線運維事件。任何一臺元數據服務器出現故障,也不需要立刻做出反應。系統繼續正常運行,運維人員則可以從容地處理問題。這是確保高可用性的關鍵所在。

主從模型本可以簡化程序的結構,因為客戶端只需要向主服務器發出請求,訪問元數據。但如同前面所描述的,可靠性、可用性和一致性的要求促使主從之間進行并發訪問,以彌補這些特性方面的漏洞。這實際上就是將原本在元數據系統之外的多副本訪問邏輯移到主服務器中,卻憑空增加了延遲,以及主從切換的麻煩。

在一致性方面,主從模型在沒有考慮軟硬件異常和數據退化的情況下,基本上沒有什么難點。但因為現實中沒有軟硬件異常是不可能的,數據退化也是時刻在發生的。于是,無論主、從服務器都可能缺少數據,更無法單純通過主服務器來維持數據的一致性。為了獲得盡可能高的一致性,主從模型也需要通過整合主從副本來實現一致性保障,而副本修復也同樣是不可缺少的一部分。實際上,無論是主還是從,都應當看作是一個元數據的副本,既然是多個副本,那么也就存在一致性的問題。多副本遇到的問題,主從模型同樣也會遇到,這就是主從模型不如多副本模型來得合用的原因。

主從模型的主要優勢是可以執行復雜的數據庫邏輯,如關聯、聚合等。但這在多副本模型下非常難。主從模型下,一個復雜的查詢得到執行后,將冪等的結果數據同步到從服務器。而對多副本模型來說,每個副本獨自處理查詢,會產生混亂的結果,因為復雜查詢往往是非冪等的。

對象存儲之所以可以使用多副本,是因為對象存儲的業務模型已被簡化到不需要復雜查詢的地步。所有寫入操作都只是增加一條元數據而已,天生的冪等操作。對象存儲放棄目錄結構,只實現Key/Value模型,也是為了避免復雜查詢的存在。

總結

在對象存儲中,元數據用于保存數據存儲位置、數據屬性等信息。元數據的好壞關系到整個對象存儲系統的可靠性、可用性、一致性等方面。元數據有如此重要的功能,必須有強有力的保障加以支撐。

元數據的存在雖然表面上增加了系統的復雜性,但實際上是將一致性保障、數據存儲基準、可靠性檢測和修復、數據統計等重要的功能集中到更小的數據量上,更加易于實現和操作。這在去中心化的方案中是難以實現的。

元數據的兩種主要模型包括主從模型和多副本模型。主從模型,作為常規的數據庫高可用手段,并不能滿足云存儲系統的諸多特性。而多副本模型則能更好地平衡各方面需求,同時也很好地平衡了研發、部署和運維等方面的要求。

多副本模型的核心難點集中在一致性保障方面,針對這些問題都有相應的解決手段,但都無法完全消除問題的存在。綜合運用各種保障方法,可以極大地減少一致性問題的發生概率,最終將其降低到服務可以接受的程度。

鏈接已復制,快去分享吧

企業網版權所有?2010-2024 京ICP備09108050號-6京公網安備 11010502049343號

  • <menuitem id="jw4sk"></menuitem>

    1. <form id="jw4sk"><tbody id="jw4sk"><dfn id="jw4sk"></dfn></tbody></form>
      主站蜘蛛池模板: 广宁县| 会理县| 云阳县| 济源市| 无极县| 彭山县| 曲沃县| 贵定县| 兰西县| 东港市| 宁德市| 萝北县| 卫辉市| 芜湖县| 苏尼特右旗| 天台县| 永吉县| 海原县| 洪江市| 曲麻莱县| 皋兰县| 蒙城县| 阿拉尔市| 清镇市| 高邑县| 嫩江县| 高邑县| 谷城县| 松桃| 故城县| 木里| 弥勒县| 易门县| 万宁市| 铜陵市| 南投县| 华容县| 哈密市| 原平市| 扎囊县| 鸡泽县|