Bayou複製分散式儲存系統

LightningStar發表於2021-10-11

本文主要參考文獻[1]完成。

第1章導讀

Bayou是一個複製的、弱一致性的儲存系統,用於移動計算環境。為了最大化可用性,Bayou為使用者提供了可以任意讀寫訪問的副本。Bayou的設計側重於為應用程式提供一套檢查和解決更新衝突的機制,確保整個系統趨向最終一致性。Bayou提供了一套協議,通過這個協議,解決衝突時可以使系統保持一致。

Bayou的衝突檢測方法被稱為依賴性檢查。為了保證最終一致性,bayou 伺服器必須能夠回滾先前執行的寫操作的效果,並根據全域性序列化順序重做它們。此外,bayou 允許客戶端觀察伺服器接收到的所有寫操作的結果,包括尚未最終解決衝突的暫時寫操作。

Bayou複製儲存系統的目標是支援各種非實時協作性的應用,諸如日曆、電子郵件、書目資料庫等。

bayou的目標是為處於不可靠網路連線狀態下的移動裝置構建一個滿足最終一致性的分散式儲存系統。bayou不能保證應用程式讀寫的資料一定是處於一致性狀態的。

第2章 Bayou基本系統模型

在 Bayou系統中,部署在伺服器(虛擬伺服器,非實體伺服器)中的每個data collection(資料收集中心)都是一份完整的備份。客戶端通過Bayou提供的API與資料中心進行互動。這些基於RPC實現的API提供了兩個基本功能:讀和寫。
image_57

在Bayou系統中,客戶端和伺服器可以同時執行在同一個主機中。Bayou中的server在接受client的寫請求之後,client並不會等待server與其他server進行同步。因為Bayou是弱一致性的,要儘可能提高系統可用性(availability)、簡易性(simplicity)、可伸縮性(scalability).

雖然單獨的讀寫操作是在單個伺服器上執行的,但是客戶機不必侷限於與單個伺服器進行互動。實際上,在移動計算環境中,伺服器之間的切換通常是可取的,bayou 提供會話保證,以減少訪問不同伺服器時客戶端觀察到的不一致。

為了在各個server之間處理衝突,server會為每個寫操作提供一個全域性唯一的WriteID。該ID由第一個接受該寫請求的server提供。每個伺服器在本地執行寫操作時都會執行衝突檢測和解決。

為了儘可能減少伺服器之間的網路通訊,bayou僅在成對通訊的節點間傳播寫操作,這被稱之為anti-entropy 會話。

第3章 衝突檢測與解決

衝突檢測的難點:粒度選擇。如果粒度選擇過大,如將一個檔案作為粒度,將會出現檔案替換情況導致資料丟失;如果粒度過小,如將每次操作記錄作為粒度,將會檢測不出來衝突。因此衝突的定義需要由應用程式來定義。

Bayou提供了依賴檢查(dependency checks)來檢查衝突,採用合併過程(merge procedures)來處理衝突。

Bayou_Write(update, dependency_check, mergeproc){
    if(DB_Eval(dependency_check.query) != dependency_check.expected_result)
    {
        resolved_update = Interpret(mergeproc);
    }
    else
    {
        resolved_update = update;
    }
    DB_Apply(resolved_update);
}

本質上,bayou系統要求應用開發者向Bayou_Write傳入三個函式指標,分別執行更新、衝突檢查和合並過程。即,bayou只是將三個函式進行打包成一個寫操作,在後文中的所有對寫操作的描述都是對Bayou_Write的描述。

3.1依賴檢查

與應用相關的衝突檢測是通過Bayou系統的依賴檢查實現的。每個寫操作都包含一個依賴檢查,每個依賴檢查是由程式提供的查詢語句和它期望的結果組成的。當伺服器執行的查詢語句與所擁有的資料副本不吻合時,將不會返回期望的結果,這樣就檢測到了衝突。這種依賴檢查是執行更新操作的前提條件。如果依賴檢查失敗,將不會執行該更新操作,而是開始執行合併過程以解決衝突。依賴檢查可以檢測讀寫衝突。

3.2合併過程

在寫操作中會提供一個合併過程以供檢測到衝突時解決衝突呼叫。該合併過程是使用高語義的解釋型語言實現的。

在實踐中,Bayou合併過程是由應用程式開發者以模板的形式編寫的。模板例項化時需要為每個write填充實現細節。

應用程式的使用者不需要知道合併過程,除非程式無法解決衝突。在無法實現自動解決的情況下,合併過程仍將執行到完成,但預計將產生一個經過修訂的更新,以某種方式記錄檢測到的衝突,使使用者能夠在稍後解決衝突。為了實現手動解決,可能使用互動式合併工具,必須以允許使用者理解所發生的事情的方式向使用者呈現衝突的更新。按照慣例,大多數Bayou資料收集都包含無法解決的衝突的錯誤日誌。但是,此類約定不在Bayou儲存系統的域中,可能會因應用程式而異。

當檢測到衝突並且在處理衝突的過程中,Bayou依然對外提供資料的可訪問性。

第4章 副本的一致性

Bayou系統保證通過反熵會話接收所有寫操作,並且兩個擁有相同寫操作集合的伺服器將具有相同的資料內容。但是,bayou不強制限制寫傳播延遲。即,bayou系統僅能夠保證最終一致性。bayou保證所有的write操作將以定義好的順序執行,且每次執行的效果是相同的,並且衝突檢測和合並過程是確定的,以使對衝突的檢測和解決的行為是一致的。

這裡的內容核心是定義了寫入操作的兩種狀態:提交(committed)和臨時(tentative)。

對於所有不再被重做的寫入操作稱之為穩定(stability)。處於提交狀態的寫是穩定的。

4.1臨時寫

bayou的兩個重要特性保證了最終一致性:

  1. 在所有伺服器上,寫操作都以相同的、定義良好的順序執行;
  2. 衝突檢測和合並過程是確定的,伺服器將以同樣的方式解決相同的衝突。

當Bayou伺服器從客戶端接受寫入時最初被認為是試探性的。試探性寫入根據其接受伺服器分配給它們的時間戳進行排序。最終,通過後文描述的提交過程提交每個寫入。已提交寫的順序是根據它們提交的時間和在任何臨時寫之前。

對於臨時寫,唯一的要求是在同一個伺服器上被賦予單調遞增的時間戳。這樣通過<timestamp, WriteID>對就能對同一個伺服器上的所有寫操作進行排序。在不同的伺服器之間沒有要求對時鐘進行同步(實際上在不穩定的移動式網路中也無法實現這一要求)。但是需要保持伺服器之間的時鐘需要接近。Bayou伺服器維護了一個邏輯時鐘,該邏輯時鐘通常與它的實時系統進行同步。為了保證因果順序,不同的伺服器需要在反熵會話中對邏輯時鐘進行修正。

由於伺服器的本地寫入操作已經執行,在通過反熵會話接收到其他伺服器的寫入操作之後,需要對先前的寫入操作進行撤銷操作,並與傳來的寫入操作合併以獲取一個新的寫入操作序列,並依據新的全序序列對寫入操作進行重做。

Bayou通過限制合併過程只依賴於伺服器當前的資料內容和合並過程本身提供的資料,確保在每個伺服器上獨立執行的合併過程產生一致的更新。特別是,合併過程不能訪問時變的或特定於伺服器的"環境"資訊,如當前系統時鐘或伺服器名稱。而且,由於超出資源使用限制而失敗的合併過程必須確定地失敗。這意味著所有伺服器必須在分配給合併過程的CPU和記憶體資源上設定統一的邊界,並且必須在執行期間一致地執行這些邊界。一旦滿足了這些條件,兩個以相同副本開始的伺服器將在執行Write後以相同副本結束。

4.2寫穩定和提交

一個寫入操作被稱之為是穩定(stable)的,當且僅當該伺服器上記錄該寫入操作的log被固定下來之後。因此臨時寫入操作是不穩定的,因為其log還沒有固定。因為其他伺服器可能具有該寫入操作之前的寫入操作,導致該寫入操作需要被重做。

應用程式則引入了confirmation和commitment的概念來對應bayou系統的寫穩定的概念。bayou提供了一套API以便於應用程式缺某個寫入操作是否是穩定的。

判斷寫操作是否穩定的方法如下:

  1. 每個伺服器在反熵期間不僅傳送寫入操作集合,還傳送當前邏輯時鐘的值通過適當假設寫操作的傳播順序,伺服器可以在時間戳低於所有伺服器時鐘的情況下確定寫操作是穩定的。這種方法的主要缺點是,保持斷開連線的伺服器可能會阻止"寫"的穩定,這可能導致伺服器重新連線時回滾大量的"寫";
  2. 為了加快更新的速度,在一個與某些伺服器通訊可能無法延長時間的環境中,Bayou系統使用了一個提交過程。也就是說,當一個Write被顯式提交時,它就會變得穩定,事實上,在Bayou系統中,我們通常會交替使用術語"穩定"和"提交"。已提交的寫(按提交順序)放在每個伺服器的寫日誌中任何暫定的寫(Write)之前。這一點,再加上Bayou的反熵協議,確保伺服器按照提交的順序瞭解提交的寫操作,從而提供了穩定性。

4.3 小結

bayou採取主伺服器方案。這個方案要求指定某個server作為主伺服器。在反熵過程中,主server將指定哪些寫入是committed,以及它們該以什麼樣的順序執行這些寫入操作,並將這些資訊傳遞給其他伺服器。每個複製的資料集都可以指定不同的server作為主伺服器。

bayou只是儘可能保證寫入操作的提交是根據臨時寫順序的時間戳進行排序的,但是並不保證這一點。

第5章 儲存系統實現問題

bayou設計對底層儲存系統有幾點要求:

  • 高效的日誌記錄
  • 高效的撤銷/重做
  • 對committed和tentative資料提供不同的檢視
  • 支援伺服器間的反熵操作

實現的三個元件:

  • 寫入日誌

  • 元組儲存
    執行寫入操作和響應讀取請求的資料庫。執行在記憶體的關係型資料庫。

  • 撤銷日誌

image_58

5.1 元組儲存

對外提供了兩個檢視,committed和full。臨時寫的效果反映在full檢視,committed寫的效果體現在committed檢視和full檢視。一個臨時刪除的操作可能會導致一個元組出現在committed檢視但是full檢視則不存在了。

元組資料庫使用2bit來標記某個元組是屬於full檢視還是committed檢視。這樣可以減少儲存空間(因為full檢視和committed檢視的資料是高度重合的),同時也使得對元組資料在full和committed檢視之間的轉換提供了方便,另外也便於查詢操作。

為了支援反熵操作,維護了兩個時間戳向量:C向量和F向量。

C向量表示最後一個committed Write執行完畢後的元組儲存的時間戳,F向量表示writelog中最後一個臨時寫執行完畢後的元組儲存的時間戳。用於指明哪些寫操作需要在反熵中被傳遞。

為了防止在反熵期間重複接收相同的寫操作,伺服器維護了一個時間戳向量O向量(ommitted vector),每個伺服器都儲存從指定伺服器接收到的最新的寫操作的時間戳。

5.2 崩潰恢復

處於恢復的目的,完整的write log和tuple store的檢查點都維護在外存上。undo log則只維護在記憶體中。

第6章 訪問控制

授權粒度:一個資料集合。

許可權:讀許可權、寫許可權、server許可權(即建立一個新的資料集合副本)

每個使用者都擁有一個公私鑰對和一組訪問控制證書。在啟動時,使用者從相應的使用者獲取金鑰和證書。

Bayou使用三種證書來控制授予、委派和撤銷對資料集的訪問權:

  • AC[PU, P, D] 對擁有公鑰PU的使用者在資料集D上授予P(read/writ/server)許可權;
  • D[PU, C, PY] 公鑰為PY的使用者使用相應的證書C將自己的許可權也同樣地委派給公鑰為PU的使用者
  • R[C, PY] 公鑰為PY的使用者撤銷所有通過C證書獲取許可權的使用者的許可權

第7章 Bayou的特點

  • 衝突檢測和解決需要引用程式參與
  • 衝突檢測與應用相關
  • 每個write操作都包括一個合併過程,一旦寫衝突則執行合併過程
  • 區域性和多物件更新。Bayou的Write操作可以自動地對一個或多個資料物件執行插入、部分修改和刪除操作
  • 臨時寫和穩定寫
  • 安全。有完整的身份驗證和訪問控制機制

第8章 思考

Bayou_Write的原子性問題

在前文對Bayou_Write的虛擬碼描述中,我們可以看到,在執行寫操作之前會先進行衝突檢查,如果檢查到衝突,那麼就需要執行合併過程解決衝突,最後再執行寫操作。這是一個非常複雜的過程,如果Bayou_Write本身不提供原子性,那麼很容易導致寫寫衝突。即,當檢查衝突並解決衝突之後,由於程式切換,另一個程式對同一個資料進行了更改,這樣在切換回原來的程式之後,這個程式認為是不存在衝突的(因為已經解決了),但是實際上已經發生了衝突。這只是其中的一種情況,更多情況請讀者自行思考。因此考慮Bayou_Write的原子性是很有必要的。

如何設定主伺服器

這個問題比較複雜,也是一個共識問題。這已經超出了本文討論範圍。

第9章 參考文獻


  1. TERRY D B, THEIMER M M, PETERSEN K, 等. Managing Update Conflicts in Bayou, a Weakly Connected Replicated Storage System[J]. [日期不詳]: 12. . ↩︎

相關文章