隨筆 - 16  文章 - 1  trackbacks - 0
          <2025年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          常用鏈接

          留言簿

          隨筆檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          Two-phase commit(http://en.wikipedia.org/wiki/Two-phase_commit_protocol)是分布式事務最基礎的協議,Three-phase commit(http://en.wikipedia.org/wiki/Three-phase_commit_protocol)主要解決Two-phase commit中協調者宕機問題。

          Two-phase commit的算法實現 (from <<Distributed System: Principles and Paradigms>>):

          協調者(Coordinator):

              write START_2PC to local log;

              multicast VOTE_REQUEST to all participants;

              while not all votes have been collected {

                  wait for any incoming vote;

                  if timeout {

                      write GLOBAL_ABORT to local log;

                      multicast GLOBAL_ABORT to all participants;

                      exit;

                  }

                  record vote;

              }

              if all participants sent VOTE_COMMIT and coordinator votes COMMIT {

                  write GLOBAL_COMMIT to local log;

                  multicast GLOBAL_COMMIT to all participants;

              } else {

                  write GLOBAL_ABORT to local log;

                  multicast GLOBAL_ABORT to all participants;

              }

          參與者(Participants)

              write INIT to local log;

              wait for VOTE_REQUEST from coordinator;

              if timeout {

                  write VOTE_ABORT to local log;

                  exit;

              }

              if participant votes COMMIT {

                  write VOTE_COMMIT to local log;

                  send VOTE_COMMIT to coordinator;

                  wait for DECISION from coordinator;

                  if timeout {

                      multicast DECISION_REQUEST to other participants;

                      wait until DECISION is received;  /* remain blocked*/

                      write DECISION to local log;

                  }

                  if DECISION == GLOBAL_COMMIT

                      write GLOBAL_COMMIT to local log;

                  else if DECISION == GLOBAL_ABORT

                      write GLOBAL_ABORT to local log;

              } else {

                  write VOTE_ABORT to local log;

                  send VOTE_ABORT to coordinator;

              }

          另外,每個參與者維護一個線程專門處理其它參與者的DECISION_REQUEST請求,處理線程流程如下:

              while true {

                  wait until any incoming DECISION_REQUEST is received;

                  read most recently recorded STATE from the local log;

                  if STATE == GLOBAL_COMMIT

                      send GLOBAL_COMMIT to requesting participant;

                  else if STATE == INIT or STATE == GLOBAL_ABORT;

                      send GLOBAL_ABORT to requesting participant;

                  else

                      skip;  /* participant remains blocked */

              }

          從上述的協調者與參與者的流程可以看出,如果所有參與者VOTE_COMMIT后協調者宕機,這個時候每個參與者都無法單獨決定全局事務的最終結果(GLOBAL_COMMIT還是GLOBAL_ABORT),也無法從其它參與者獲取,整個事務一直阻塞到協調者恢復;如果協調者出現類似磁盤壞這種永久性錯誤,該事務將成為被永久遺棄的孤兒。問題的解決有如下思路:

          1. 協調者持久化數據定期備份。為了防止協調者出現永久性錯誤,這是一種代價最小的解決方法,不容易引入bug,但是事務被阻塞的時間可能特別長,比較適合銀行這種正確性高于一切的系統。

          2. Three-phase Commit。這是理論上的一種方法,實現起來復雜且效率低。思路如下:假設參與者機器不可能出現超過一半同時宕機的情況,如果協調者宕機,我們需要從活著的超過一半的參與者中得出事務的全局結果。由于不可能知道已經宕機的參與者的狀態,所以引入一個新的參與者狀態PRECOMMIT,參與者成功執行一個事務需要經過INIT, READY, PRECOMMIT,最后到COMMIT狀態;如果至少有一個參與者處于PRECOMMIT或者COMMIT,事務成功;如果至少一個參與者處于INIT或者ABORT,事務失敗;如果所有的參與者都處于READY(至少一半參與者活著),事務失敗,即使原先宕機的參與者恢復后處于PRECOMMIT狀態,也會因為有其它參與者處于ABORT狀態而回滾。PRECOMMIT狀態的引入給了宕機的參與者回滾機會,所以Three-phase commit在超過一半的參與者活著的時候是不阻塞的。不過,Three-phase Commit只能算是是理論上的探索,效率低并且沒有解決網絡分區問題。

          3. Paxos解決協調者單點問題。Jim Gray和Lamport合作了一篇論文講這個方法,很適合互聯網公司的超大規模集群,Google的Megastore事務就是這樣實現的,不過問題在于Paxos和Two-phase Commit都不簡單,需要有比較靠譜(代碼質量高)的小團隊設計和編碼才行。后續的blog將詳細闡述該方法。

          總之,分布式事務只能是系統開發者的烏托邦式理想,Two-phase commit的介入將導致涉及多臺機器的事務之間完全串行,沒有代價的分布式事務是不存在的。

           

          posted @ 2009-12-22 23:01 Programmers 閱讀(856) | 評論 (0)編輯 收藏

          前面我的一篇文章http://hi.baidu.com/knuthocean/blog/item/12bb9f3dea0e400abba1673c.html引用了對Google App Engine工程師關于Bigtable/Megastore replication的文章。當時留下了很多疑問,比如:為什么Google Bigtable 是按照column family級別而不是按行執行replication的?今天重新思考了Bigtable replication問題,有如下體會:

          1. Bigtable/GFS的設計屬于分層設計,和文件系統/數據庫分層設計原理一致,通過系統隔離解決工程上的問題。這種分層設計帶來了兩個問題,一個是性能問題,另外一個就是Replication問題。由于存儲節點和服務節點可能不在一臺機器,理論上總是存在性能問題,這就要求我們在加載/遷移Bigtable子表(Bigtable tablet)的時候考慮本地化因素;另外,GFS有自己的replication機制保證存儲的可靠性,Bigtable通過分離服務節點和存儲節點獲得了很大的靈活性,且Bigtable的宕機恢復時間可以做到很短。對于很多對實時性要求不是特別高的應用Bigtable由于服務節點同時只有一個,既節約資源又避免了單點問題。然后,Bigtable tablet服務過于靈活導致replication做起來極其困難。比如,tablet的分裂和合并機制導致多個tablet(一個只寫,其它只讀)服務同一段范圍的數據變得幾乎不可能。

          2. Google replication分為兩種機制,基于客戶端和基于Tablet Server。分述如下:

          2-1). 基于客戶端的replication。這種機制比較簡單,實現如下:客戶端讀/寫操作均為異步操作,每個寫操作都嘗試寫兩個Bigtable集群,任何一個寫成功就返回用戶,客戶端維護一個retry list,不斷重試失敗的寫操作。讀操作發到兩個集群,任何一個集群讀取成功均可。然后,這樣做有兩個問題:

              a. 客戶端不可靠,可能因為各種問題,包括程序問題退出,retry list丟失導致兩個集群的數據不一致;

              b. 多個客戶端并發操作時無法保證順序性。集群A收到的寫操作可能是"DEL item; PUT item";集群B的可能是"PUT item; DEL item"。

          2-2). 基于Tablet Server的replication。這種機制實現較為復雜,目的是為了保證讀服務,寫操作的延時仍然可能比較長。兩個集群,一個為主集群,提供讀/寫服務;一個為slave集群,提供只讀服務,兩個集群維持最終一致性。對于一般的讀操作,盡量讀取主集群,如果主集群不可以訪問則讀取slave集群;對于寫操作,首先將寫操作提交到主集群的Tablet Server,主集群的Tablet Server維護slave集群的元數據信息,并維護一個后臺線程不斷地將積攢的用戶表格寫操作提交到slave集群進行日志回放(group commit)。對于一般的tablet遷移,操作邏輯和Bigtable論文中的完全一致;主集群如果發生了機器宕機,則除了回放commit log外,還需要完成宕機的Tablet Server遺留的后臺備份任務。之所以要按照column family級別而不是按行復制,是為了提高壓縮率從而提高備份效率。如果主集群寫操作日志的壓縮率大于備份數據的壓縮率,則可能出現備份不及時,待備份數據越來越多的問題。

          假設集群A為主集群,集群B是集群A的備份,集群切換時先停止集群A的寫服務,將集群A余下的備份任務備份到集群B后切換到集群B;如果集群A不可訪問的時間不可預知,可以選擇直接切換到集群B,這樣會帶來一致性問題。且由于Bigtable是按列復制的,最后寫入的一些行的事務性無法保證。不過由于寫操作數據還是保存在集群A的,所以用戶可以知道丟了哪些數據,很多應用可以通過重新執行A集群遺留的寫操作進行災難恢復。Google的App Engine也提供了這種查詢及重做丟失的寫操作的工具。

          想法不成熟,有問題聯系:knuthocean@163.com

          posted @ 2009-12-18 22:05 Programmers 閱讀(389) | 評論 (0)編輯 收藏

          負載平衡策略

          Dynamo的負載平衡取決于如何給每臺機器分配虛擬節點號。由于集群環境的異構性,每臺物理機器包含多個虛擬節點。一般有如下兩種分配節點號的方法:

          1. 隨機分配。每臺物理節點加入時根據其配置情況隨機分配S個Token(節點號)。這種方法的負載平衡效果還是不錯的,因為自然界的數據大致是比較隨機的,雖然可能出現某段范圍的數據特別多的情況(如baidu, sina等域名下的網頁特別多),但是只要切分足夠細,即S足夠大,負載還是比較均衡的。這個方法的問題是可控性較差,新節點加入/離開系統時,集群中的原有節點都需要掃描所有的數據從而找出屬于新節點的數據,Merkle Tree也需要全部更新;另外,增量歸檔/備份變得幾乎不可能。

          2. 數據范圍等分+隨機分配。為了解決方法1的問題,首先將數據的Hash空間等分為Q = N * S份 (N=機器個數,S=每臺機器的虛擬節點數),然后每臺機器隨機選擇S個分割點作為Token。和方法1一樣,這種方法的負載也比較均衡,且每臺機器都可以對屬于每個范圍的數據維護一個邏輯上的Merkle Tree,新節點加入/離開時只需掃描部分數據進行同步,并更新這部分數據對應的邏輯Merkle Tree,增量歸檔也變得簡單。該方法的一個問題是對機器規模需要做出比較合適的預估,隨著業務量的增長,可能需要重新對數據進行劃分。

          不管采用哪種方法,Dynamo的負載平衡效果還是值得擔心的。

          客戶端緩存及前后臺任務資源分配

          客戶端緩存機器信息可以減少一次在DHT中定位目標機器的網絡交互。由于客戶端數量不可控,這里緩存采用客戶端pull的方式更新,Dynamo中每隔10s或者讀/寫操作發現緩存信息不一致時客戶端更新一次緩存信息。

          Dynamo中同步操作、寫操作重試等后臺任務較多,為了不影響正常的讀寫服務,需要對后臺任務能夠使用的資源做出限制。Dynamo中維護一個資源授權系統。該系統將整個機器的資源切分成多個片,監控60s內的磁盤讀寫響應時間,事務超時時間及鎖沖突情況,根據監控信息算出機器負載從而動態調整分配給后臺任務的資源片個數。

          Dynamo的優點

          1. 設計簡單,組合利用P2P的各種成熟技術,模塊劃分好,代碼復用程度高。

          2. 分布式邏輯與單機存儲引擎邏輯基本隔離。很多公司有自己的單機存儲引擎,可以借鑒Dynamo的思想加入分布式功能。

          3. NWR策略可以根據應用自由調整,這個思想已經被Google借鑒到其下一代存儲基礎設施中。

          4. 設計上天然沒有單點,且基本沒有對系統時鐘一致性的依賴。而在Google的單Master設計中,Master是單點,需要引入復雜的分布式鎖機制來解決,且Lease機制需要對機器間時鐘同步做出假設。

          Dynamo的缺陷

          1. 負載平衡相比單Master設計較不可控;負載平衡策略一般需要預估機器規模,不能無縫地適應業務動態增長。

          2. 系統的擴展性較差。由于增加機器需要給機器分配DHT算法所需的編號,操作復雜度較高,且每臺機器存儲了整個集群的機器信息及數據文件的Merkle Tree信息,機器最大規模只能到幾千臺。

          3. 數據一致性問題。多個客戶端的寫操作有順序問題,而在GFS中可以通過只允許Append操作得到一個比較好的一致性模型。

          4. 數據存儲不是有序,無法執行Mapreduce;Mapreduce是目前允許機器故障,具有強擴展性的最好的并行計算模型,且有開源的Hadoop可以直接使用,Dynamo由于數據存儲依賴Hash無法直接執行Mapreduce任務。

           

          posted @ 2009-12-05 15:19 Programmers 閱讀(1778) | 評論 (0)編輯 收藏

          異常處理

          Dynamo中把異常分為兩種類型,臨時性的異常和永久性異常。服務器程序運行時一般通過類似supervise的監控daemon啟動,出現core dump等異常情況時自動重啟。這種異常是臨時性的,其它異常如硬盤報修或機器報廢等由于其持續時間太長,稱之為永久性的。回顧Dynamo的設計,一份數據被寫到N, N+1, ... N+K-1這K臺機器上,如果機器N+i (0 <= i <= K-1)宕機,原本寫入該機器的數據轉移到機器N+K,機器N+K定時ping機器N+i,如果在指定的時間T內N+i重新提供服務,機器N+K將啟動傳輸任務將暫存的數據發送給機器N+i;如果超過了時間T機器N+i還是處于宕機狀態,這種異常被認為是永久性的,這時需要借助Merkle Tree機制進行數據同步。這里的問題在于時間T的選擇,所以Dynamo的開發人員后來干脆把所有程序檢測出來的異常認為是臨時性的,并提供給管理員一個utility工具,用來顯示指定一臺機器永久性下線。由于數據被存儲了K份,一臺機器下線將導致后續的K臺機器出現數據不一致的情況。這是因為原本屬于機器N的數據由于機器下線可能被臨時寫入機器N+1, ... N+K。如果機器N出現永久性異常,后續的K臺機器都需要服務它的部分數據,這時它們都需要選擇冗余機器中較為空閑的一臺進行同步。Merkle Tree同步的原理很簡單,每個非葉子節點對應多個文件,為其所有子節點值組合以后的Hash值,葉子節點對應單個數據文件,為文件內容的Hash值。這樣,任何一個數據文件不匹配都將導致從該文件對應的葉子節點到根節點的所有節點值不同。每臺機器維護K棵Merkle Tree,機器同步時首先傳輸Merkle Tree信息,并且只需要同步從根到葉子的所有節點值均不相同的文件。

          讀/寫流程

          客戶端的讀/寫請求首先傳輸到緩存的一臺機器,根據預先配置的K、W和R值,對于寫請求,根據DHT算法計算出數據所屬的節點后直接寫入后續的K個節點,等到W個節點返回成功時返回客戶端,如果寫請求失敗將加入retry_list不斷重試。如果某臺機器發生了臨時性異常,將數據寫入后續的備用機器并在備用機器中記錄臨時異常的機器信息。對于讀請求,根據DHT算法計算出數據所屬節點后根據負載策略選擇R個節點,從中讀取R份數據,如果數據一致,直接返回客戶端;如果數據不一致,采用vector clock的方法解決沖突。Dynamo系統默認的策略是選擇最新的數據,當然用戶也可以自定義沖突處理方法。每個寫入系統的<key, value>對都記錄一個vector lock信息,vector lock就是一系列<機器節點號, 版本號/時間戳>對,記錄每臺機器對該數據的最新更新版本信息。如下圖:


          讀取時進行沖突解決,如果一臺機器讀到的數據的vector lock記錄的所有版本信息都小于另一臺機器,直接返回vector lock較大的數據;如果二者是平行版本,根據時間戳選擇最新的數據或者通過用戶自定義策略解決沖突。讀請求除了返回數據<key, value>值以外還返回vector lock信息,后續的寫操作需要帶上該信息。

          問題1:垃圾數據如何回收?

          Dynamo的垃圾回收機制主要依賴每個節點上的存儲引擎,如Berkely db存儲引擎,merge-dump存儲引擎等。其它操作,如Merkle Tree同步產生的垃圾文件回收可以和底層存儲引擎配合完成。

          問題2:Dynamo有沒有可能丟數據?

          關鍵在于K, W, R的設置。假設一個讀敏感應用設置K=3, W=3, R=1,待處理的數據原本屬于節點A, B, C,節點B出現臨時性故障的過程中由節點D代替。在節點B出現故障到節點B同步完成節點D暫存的修改這段時間內,如果讀請求落入節點B或者D都將出現丟數據的問題。這里需要適當處理下,對于B節點下線的情況,由于其它機器要么緩存了B節點已下線信息,要么讀取時將發現B節點處于下線狀態,這是只需要將請求轉發其它節點即可;對于B節點上線情況,可以等到B節點完全同步以后才開始提供讀服務。對于設置W<K的應用,Dynamo讀取時需要解決沖突,可能丟數據。總之,Dynamo中可以保證讀取的機器都是有效的(處于正常服務狀態),但W != K時不保證所有的有效機器均同步了所有更新操作。

          問題3:Dynamo的寫入數據有沒有順序問題?

          假設要寫入兩條數據"add item"和"delete item",如果寫入的順序不同,將導致完全不同的結果。如果設置W=K,對于同一個客戶端,由于寫入所有的機器以后才返回,可以保證順序;而多個客戶端的寫操作可能被不同的節點處理,不能保證順序性。如果設置W < K,Dynamo不保證順序性。

          問題4:沖突解決后是否需要將結果值更新存儲節點?

          讀操作解決沖突后不需要將結果值更新存儲節點。產生沖突的情況一般有機器下線或者多個客戶端導致的順序問題。機器下線時retry_list中的操作將丟失,某些節點不能獲取所有的更新操作。對于機器暫時性或者永久性的異常,Dynamo中內部都有同步機制進行處理,但是對于retry_list中的操作丟失或者多個客戶端引發的順序問題,Dynamo內部根本無法分辨數據是否正確。唯一的沖突解決機器在讀操作,Dynamo可以設計成讀操作將沖突解決結果值更新存儲節點,但是這樣會使讀操作變得復雜和不高效。所以,比較好的做法是每個寫操作都帶上讀操作返回的多個版本數據,寫操作將沖突處理的結果更新存儲節點。

          posted @ 2009-12-04 23:05 Programmers 閱讀(1063) | 評論 (0)編輯 收藏
          分布式系統或其它論文里面經常出現下面幾個名詞:
          樂觀鎖:有時稱作optimistic concurrency control, 指并發控制的時候“樂觀”地認為沖突的概率很小,萬一發生了沖突再重試。具體表現為事務執行過程中不鎖住其它事務,等到事務提交的時候看一下是否發生了沖突,如果沖突則重試或回滾,否則提交事務。
          悲觀鎖:并發控制的時候總是很悲觀,事務執行過程中鎖住其它事務,事務提交時不會有沖突。
          從表面上看,悲觀鎖比較符合計算機基礎課上灌輸的思維,然而,在分布式系統環境下,異常是常有的事。假設分布式系統采用悲觀鎖設計,如果客戶端發出事務(加鎖)請求后異常退出,將導致系統被永久鎖住。Web應用存儲系統一般采用樂觀鎖設計,這和Web應用的讀/寫比例一般超過10相關。系統設計的時候面臨這樣一種CAS(Compare-And-Swap)需求:如果待操作項符合某個條件則修改。我們可以采用悲觀鎖鎖住待操作項的所有修改,再加上鎖的最大持有時間限制,但這樣的API設計風險很大,樂觀鎖可以很好地解決該問題。

          coarse-grained vs fine-grained:粗粒度和細粒度。J2EE中常用來指API的粒度,比如, 我有一個遠程對象, 他有很多屬性和對應的getter和setter方法, 如果我們遠程調用對象每個屬性的getter和setter方法, 就會產生很多遠程方法調用. 這就是fine-grained, 會造成性能問題。所以我們可以用一個setdata或getdata的方法把一些屬性的訪問封裝起來, 只用一個遠程方法傳輸一個data transfer object來對該對象進行賦值和訪問, 這就是coarse-grained。Google Chubby中用來表示鎖的粒度。coarse-grained指的是分布式鎖的持有時間可以很長并不斷延長鎖的持有時間,這樣的好處在于對鎖服務器的壓力較小,難點在于鎖服務端宕機恢復需要恢復鎖的狀態,find-grained指的是分布式鎖的持有時間一般是秒級或者毫秒級,這樣的好處在于鎖服務器宕機恢復不必維持原有鎖的狀態,但這種簡單的設計方法導致服務器壓力很大,不容易擴展到大集群。Google的設計一開始就把集群的線性擴展放到了一個很重要的位置,所以Google Chubby里面使用了coarse-grained的設計。客戶端可以簡單地在coarse-grained鎖的基礎上擴展出一個fine-grained的鎖,具體請看Chubby論文:scholar.google.cn/scholar
          posted @ 2009-12-03 14:58 Programmers 閱讀(528) | 評論 (0)編輯 收藏
          Google在SIGMOD 2008上透露了Megastore部分實現細節,詳情參考大牛James Hamilton的blog:perspectives.mvdirona.com/2008/07/10/GoogleMegastore.aspx
          大牛的文章固然不錯,不過肯定不大好懂,下面我說一下我對文章的翻譯+理解:
          1. Google Bigtable只支持最簡單的insert, update, del, ...等函數調用API,不支持SQL形式的API,這個轉換工作放到了Megastore層次上來做。SQL對于異步Bigtable調用的支持需要仔細考慮。
          2. 對于索引支持文章中已經說得很明顯了,維護一個<索引,row_key>的索引表,更新時先更新數據表再更新索引表,索引項越多,更新效率越低,但是讀基本不怎么影響,特別適合互聯網這種讀/寫比例一般超過10倍的應用。
          3. Megastore不提供通用的分布式事務支持,分布式事務僅僅限于同一個entity group。Bigtable支持單行的事務,而Megastore支持row key前綴相同的多行事務,如一個用戶的blog, post, photo,可以將它們存在到Bigtable的一張表中,row key為user_id + blog_id + post_id + photo_id,這樣同一個user的數據即為一個entity group。然而,這樣就導致不能支持像百付寶、支付寶等電子商務轉賬事務,我暫時也還不清楚支持同一個entity group內部的事務意義有多大,即有多少web應用需要這種同一個entity group下的事務支持。
          4. Megastore支持事務的方式當然還是傳統的Two-phase commit協議,為了解決這個協議中協調者失效導致的問題,引入Paxos協議(Google Chubby)使協調者不再成為單點。具體做起來會非常復雜,這里提供超級大牛Jim Gray和Lamport的一篇論文供大家參考:scholar.google.com/scholar   個人認為Oracle的事務內部是一個基本的Two-phase commit協議,協調者宕機時由Oracle DBA手工介入,由于其復雜性,對DBA要求很高,所以Taobao一直網羅國內頂級DBA牛人。
          5. Megastore具體事務實現時會借用Bigtable 原有的機制來實現commit log, replication等功能。可能的實現為:建一張專門的Entity group root表,加載Entity group root表的Tablet Server做為協調者角色進行分布式事務控制。然而問題在于加載Entity group root表的Tablet Server是一個單點,實現多個Tablet Server服務同一個Bigtable Tablet又是一件極其困難的事情。
          6. Megastore不支持復雜的Join操作,這和互聯網公司應用性質相關。Join操作一般不要求強一致性,可以通過多表冗余方式實現。
          7. 事務的并發控制采用最優控制策略。簡單來說,就是事務過程中不要鎖住其它事務操作,提交的時候看一下是否與其它事務沖突,如果有沖突則重試。Megastore實現時沒有rollback,失敗了都是retry,宕機了就回放操作日志。
          8. Megastore/Bigtable的實現者認為讓用戶自己指定entity group, locality group是合理的(和數據存儲位置相關)。這樣的效果是同一個entity group的數據經常存放在一臺機器上,分布式事務的性能損耗較小,這也就說明在分布式系統中,沒有代價的scalable是不存在的,要想獲得scalable和性能,就必須犧牲關系數據庫的一些特性及用戶的易用性。

          上述均為個人的粗淺看法,如何避免協調者的單點等很多問題還沒有想清楚,Bigtable和Megastore的replication策略看起來也有些沖突,想清楚后將續寫!
          posted @ 2009-12-03 14:58 Programmers 閱讀(616) | 評論 (0)編輯 收藏
          前文說到,Dynamo DHT能夠定位數據所屬的節點,為了處理節點失效的情況(DHT環中刪除節點),需要對節點的數據進行replication。思路如下:假設數據存儲K份,DHT定位到的數據所屬節點為N,則數據存儲在節點N, N+1, ..., N+K-1上。如果第i (0 <= i <= K-1) 臺機器宕機,則往后找一臺機器N+K臨時替代。臨時替代的機器定時ping機器N+i,等到它重啟后將這些臨時數據重新寫入N+i。機器N+i宕機的這段時間內,所有的讀寫均落入到機器[N, N+i-1]和[N+i+1, N+K]中,這段時間會出現數據一致性問題,需要引入專門的沖突解決協議,在Dynamo中是通過Lamport的vector clock實現的。如果機器N+i永久失效,機器N+K需要進行同步操作。一般來說,從機器N+i宕機開始到被認定為永久失效的時間不會太長,積累的寫操作也不會太多,可以采用Merkle Tree對機器的數據文件進行快速同步。
          為了在可用性和效率之間權衡,Dynamo的設計中允許用戶指定讀/寫個數R和W值。R和W分別表示每個讀/寫操作需要操作的副本數。只要滿足R+W > K,就可以保證在存在不超過一臺機器故障的時候,至少能夠讀到一份有效的數據。如果應用重視讀效率,可以設置W = K, R = 1;如果應用需要在讀/寫之間權衡,一般可設置W = 2, R = 2,K = 3。

          問題1:Dynamo中如何解決網絡分區問題?
          前面已經提到,DHT協議本身是無法處理網絡分區的。在Dynamo中,引入種子節點,服務器定期向種子節點輪詢整個機群的機器信息,種子節點的選擇符合一定的策略使得網絡分區問題出現概率降至工程可以接受的水平。

          問題2:如何將數據復制到多個數據中心?
          每份數據都被復制到N, N+1, ..., N+K-1這K臺機器中,為了保證這些機器屬于不同的數據中心,需要合理地設計獲取數據節點號的Hash算法。當然,Dynamo通過直接手工配置每臺機器的編號解決。看起來很山寨,不過很實用,呵呵。 閱讀全文
          類別:默認分類 查看評論
          文章來源:http://hi.baidu.com/knuthocean/blog/item/f085d72a06d4ee27d52af170.html
          posted @ 2009-12-03 13:43 Programmers 閱讀(331) | 評論 (0)編輯 收藏
          DHT全稱Distributed Hash Table (en.wikipedia.org/wiki/Distributed_hash_table),在P2P系統中經常用來定位數據所屬機器。這就涉及到一致哈希(consistent hashing)思想,分布式系統中經常出現機器上下線,如果采用通常的Hash方法來查找數據所屬機器,機器上下線將導致整個集群的數據分布被打亂。這是因為,機器上下線將導致機器序號及Hash函數的改變,一致哈希做了簡單調整:每臺機器存儲哈希值和它最為接近的數據。在Chord系統中,順時針到達的第一臺機器即為最近的機器。
          外部的數據可能首先傳輸至集群中的任意一臺機器,為了找到數據所屬機器,要求每臺機器維護一定的集群機器信息用于定位。最直觀的想法當然是每臺機器分別維護它的前一臺及后一臺機器的信息,機器的編號可以為機器IP的Hash值,定位機器最壞情況下復雜度為O(N)。可以采用平衡化思想來優化(如同平衡二叉樹優化數組/鏈表),使每一臺機器存儲O(logN)的集群機器信息,定位機器最壞情況下復雜度為O(logN)。
          首先考慮每臺機器維護前一臺及后一臺機器信息的情況,這里的問題是機器上下線導致緩存信息的不一致,我們需要設計協議使得在確定一段比較短的時間內能夠糾正這種錯誤。對于新機器加入,首先進行一次查找操作找到該機器的下一臺機器,并記錄下一臺機器的信息。機器內的每臺機器都定時向它的后繼發送心跳信息,如果后繼記錄的前一臺機器編號在二者之間,說明有新機器加入,這時需要更新后一臺機器編號為新加入編號;收到心跳信息的后繼也需要檢查,如果發送心跳的機器編號較為接近則更新為前一臺機器。機器下線將導致機器循環鏈表斷開,所以,每臺機器都維護了R個(一般取R值為3)最近的后繼信息,發現后繼節點下線時將通知其它后繼節點并加入新的替換節點。如果R個后繼節點同時下線,需要操作人員手工介入修復循環鏈。
          Chord中的每臺機器維護O(logN)的機器信息是一種空間換時間的做法,實現時需要引入額外的消息交換協議。這種做法依賴于如下前提:每臺機器維護的前一臺機器及后一臺機器除了短時間不一致外總是正確的。

          問題1:機器緩存短時間不一致有什么影響?數據正確性依靠什么保證?
          短時間可能出現緩存的機器信息不正確的情況。比如有A, C, D, E四臺機器,再加入一臺機器B,機器加入的過程中,原本屬于B的數據可能寫入到B或者C,這都是允許的。又如刪除機器C,訪問機器C的節點得不到數據。數據的可用性及一致性還需要通過額外的replication及沖突處理協議解決。
          問題2:DHT能否處理網絡分區問題?
          DHT不能處理網絡分區問題,理論上存在整個DHT被分成多個子集的情況。我想,這時侯需要外部的機制介入,如維護一臺外部機器保存所有機器列表等。 閱讀全文
          類別:默認分類 查看評論
          文章來源:http://hi.baidu.com/knuthocean/blog/item/cca1e711221dcfcca6ef3f1d.html
          posted @ 2009-12-03 13:43 Programmers 閱讀(416) | 評論 (0)編輯 收藏
          Amazon Dynamo是組合使用P2P各種技術的經典論文,對單機key-value存儲系統擴展成分布式系統有借鑒意義,值得仔細推敲。本人準備近期深入閱讀該論文,并寫下讀書筆記自娛自樂。當然,如果有志同道合的同學非常歡迎交流。以下是閱讀計劃:
          1. 一切從DHT開始。Dynamo首先要解決的就是給定關鍵字key找出服務節點的問題。Dynamo的思想與Chord有些類似,我們可以拋開replication問題,看看Chord和Dynamo是如何通過應用DHT解決服務節點定位問題的。這里面的難點當然是節點加入和刪除,尤其是多個節點并發加入/刪除。建議預先閱讀Chord論文:scholar.google.com/scholar
          2. Dynamo的replication。理解了DHT,我們需要結合replication理解服務節點定位及錯誤處理等問題。
          3. Dynamo錯誤處理。這里包括兩種類型的錯誤,一種是暫時性的,如由于程序bug core dump后重啟,另外一種是永久性的,這里用到了Merkle Tree同步技術。
          4. Dynamo讀/寫流程設計及沖突解決。這里主要涉及到一致性模型。Dynamo允許根據應用配置R和W值來權衡效率及Availability,并使用了Lamport的Vector Clock來解決沖突。
          5. Dynamo優化。主要是Load rebalance的優化。
          6. Dynamo實現。如果讓我們自己來實現Dynamo,我們應該如何劃分模塊以及實現過程中有哪些關鍵問題?
          后續將按照計劃對每個問題做閱讀筆記 :) 閱讀全文
          類別:默認分類 查看評論
          文章來源:http://hi.baidu.com/knuthocean/blog/item/8838ad34f9ae1dbdd0a2d3d7.html
          posted @ 2009-12-03 13:43 Programmers 閱讀(891) | 評論 (1)編輯 收藏
          推薦兩本分布式系統方面書籍:
          1. <<Distributed Systems - Principles and Paradigms>> Andrew S. Tanenbaum www.china-pub.com/40777&ref=ps Tanenbaum出品,必屬精品。本書條理清晰,涉及到分布式系統的方方面面,通俗易懂并附錄了分布式系統各個經典問題的論文閱讀資料,是分布式系統入門的不二選擇。感覺和以前看過的<<Introduction to Algorithm>>一樣,讀起來讓人心曠神怡,建議通讀。
          2. <<Introduction to Distributed Algorithms>> Gerard Tel www.china-pub.com/13102&ref=ps 我們老大推薦的書籍。雖然從名字看是入門型書籍,不過內容一點都不好懂,適合有一定基礎的同學。另外,千萬要注意,一定要買英文原版。 閱讀全文
          類別:默認分類 查看評論
          文章來源:http://hi.baidu.com/knuthocean/blog/item/8838ad34fbfb1fbdd1a2d364.html
          posted @ 2009-12-03 13:43 Programmers 閱讀(1215) | 評論 (0)編輯 收藏
          僅列出標題  下一頁
          主站蜘蛛池模板: 会泽县| 高雄县| 乐业县| 涿州市| 徐州市| 易门县| 从江县| 手机| 策勒县| 牡丹江市| 泾源县| 北票市| 闽侯县| 渝中区| 登封市| 长宁县| 和静县| 疏附县| 色达县| 比如县| 海原县| 宁陕县| 英德市| 邹城市| 高淳县| 西丰县| 晋中市| 花莲市| 博兴县| 肃宁县| 赤水市| 宁津县| 伊宁县| 黑山县| 嘉义县| 平顺县| 栾川县| 滕州市| 鲁甸县| 延庆县| 涿州市|