1. 程式人生 > >《Object Storage on CRAQ: High-throughput chain replication for read-mostly workloads》論文總結

《Object Storage on CRAQ: High-throughput chain replication for read-mostly workloads》論文總結

# CRAQ 論文總結 **說明**:本文為論文 **《Object Storage on CRAQ: High-throughput chain replication for read-mostly workloads》** 的個人理解,難免有理解不到位之處,歡迎交流與指正 。 **論文地址**:[CRAQ Paper](https://github.com/XutongLi/Learning-Notes/blob/master/Distributed_System/Paper_Reading/CRAQ/craq.pdf) *** ## 0. 簡介 **Chain Replication with Apportioned Queries (CRAQ)** 是一種對鏈式複製的改進,它通過在所有物件副本上分配負載,在保持強一致性的同時極大地提高了讀吞吐量。 本文主要對鏈式複製、**CRAQ** 原理以及 **CRAQ** 的一致性模型做出總結。 *** ## 1. 物件儲存 在 **基於物件** 的儲存中,資料作為整個單元呈現給應用程式。 物件儲存支援兩種基本原語: - `read` 或 `query` 操作返回儲存在物件名稱下的資料塊 - `write` 或 `update` 操作更改單個物件的狀態 物件儲存更適合於平面名稱空間,例如鍵值資料庫,而不是層次目錄結構。物件儲存簡化了支援整個物件修改的過程,通常,它們只需要考慮對特定物件的修改順序,而不是整個儲存系統。為每個物件提供一致性保證成本要低得多。 *** ## 2. 一致性模型 本文涉及到的兩種一致性模型為: - **強一致性**:系統保證對一個物件的讀寫操作都以順序執行,並且對於一個物件的讀操作總是會觀察到最新被寫入的值。 - **最終一致性**:在系統中,對一個物件的寫入仍是按順序在所有節點上應用的,但對不同節點的最終一致性讀取可能會在一段時間內(即,在寫操作應用於所有節點之前)返回過時的資料。但是,一旦所有副本都接收到寫入操作,則讀操作將不會返回比最新提交的寫操作更早的版本。事實上,如果一個 *client* 維護與特定節點的會話,那麼它也會看到單調的讀一致性。 *** ## 3. 鏈式複製 **鏈式複製 (Chain Replication、CR)** 是一種跨多個節點複製資料的方法: ![](https://img2020.cnblogs.com/blog/2035097/202007/2035097-20200709193802392-654801268.png) - 節點形成一個長度為 *C* 的鏈 - 鏈的頭部節點處理來自客戶端的所有寫操作 - 當一個節點接收到寫操作時,它將傳播到鏈中的每一個節點 - 一旦寫入到達尾部節點,它就被應用於鏈中的所有副本,並且被認為是提交的 - 當尾節點提交寫操作時,會向客戶端傳送一個回覆 - 尾部節點處理所有讀操作,因此只有提交的值才能由讀操作返回 鏈式複製實現了 **強一致性**:由於所有的讀操作都是在尾部進行的,而所有寫操作都在尾部提交,所以鏈尾可以簡單地對所有操作應用一個總的順序。 鏈式複製的簡單拓撲使得寫操作比提供強一致性的其他協議消耗更小。如在 *Raft* 中,*leader* 需要將每次寫操作都發送給所有的 *follower* ,但是 *CRAQ* 中,*head* 只需要將每一次寫操作傳送一次;並且 *Raft* 中 *leader* 需要處理讀寫操作,而 *CRAQ* 中的 *head* 只需要處理寫操作。 鏈式複製的 **故障恢復**: - 當頭節點出故障時:後續節點取代它成為頭節點,沒有丟失的已提交寫操作 - 當尾節點出故障時:前一個節點取代它成為尾節點,沒有丟失的寫操作 - 當中間節點故障時:從鏈中去掉,前一個節點需要重新發送最近的寫操作 **侷限性**:對一個物件的所有讀取必須都要轉到同一個節點,尾節點的負載很大。 *** ## 4. CRAQ ### 4.1 CRAQ原理 **CRAQ** 是鏈式複製的一種改進,它允許鏈中的任何節點執行讀操作: - *CRAQ* 每個節點可以儲存一個物件的多個版本,每個版本都包含一個單調遞增的版本號和一個附加屬性( 標識 `clean` 還是 `dirty` ) - 當節點接收到物件的新版本時(通過沿向下傳播的寫操作),該節點將此最新版本附加到該物件的列表中 - 如果節點不是尾節點,則將版本標記為 `dirty` ,並向後續節點傳遞寫操作 - 如果節點是尾節點,則將版本標記為 `clean` ,此時寫操作是 `已提交` 的。然後,尾節點在鏈中往回傳送 `ACK` 來通知其他節點提交 - 當物件版本的 `ACK` 到達節點時,該節點會將物件版本標記為 `clean` 。然後,該節點可以刪除該物件的所有先前版本 - 當節點收到物件的讀請求時: - 如果請求的物件的最新已知版本是乾淨的,則節點將返回此值 - 否則,節點將與尾節點聯絡,詢問尾節點上該物件的最後提交版本號,然後,節點返回該物件的此版本 ![](https://img2020.cnblogs.com/blog/2035097/202007/2035097-20200709193811119-1690968439.png) ![](https://img2020.cnblogs.com/blog/2035097/202007/2035097-20200709193816677-39689939.png) ### 4.2 CRAQ效能提升 **CRAQ** 相對於 **CR** 的吞吐量改進發生在兩種不同情況下: - **讀密集型工作負載**:讀操作可以在所有節點上執行,因此吞吐量與鏈長度呈線性比例關係 - **寫密集型工作負載**:大量寫操作的工作負載中,更容易讀取到 `dirty` 資料,因此對尾節點的查詢請求比較多。但是對尾節點查詢的工作負載遠低於所有讀請求都由尾節點來執行的工作負載,因此 *CRAQ* 吞吐量高於 *CR*。 ### 4.3 CRAQ的一致性模型 對於讀操作, *CRAQ* 支援三種一致性模型: - **強一致性**:*4.1* 中描述的讀操作可以使每次讀取都讀到最新寫入的資料,因此提供了強一致性 - **最終一致性**:允許節點返回未提交的新資料,即允許 *client* 可從不同的節點讀到不一致的物件版本。但是對於一個 *client* 來說,由於它與節點建立會話,所以它的讀操作是保證單調一致性的。 - **帶有最大不一致邊界的最終一致性**:允許節點返回未提交的新資料,但是有不一致性的限制,這個限制可以基於版本,也可以基於時間。如允許返回一段時間內新寫入但未提交的資料。 ### 4.4 split-brain 問題 若兩個相鄰節點之間的網路連線斷開,後面的節點會想去成為頭節點,這樣就會產生兩個頭節點。 **CRAQ** 本身並不會解決這樣的問題,所以需要外部的分散式協調服務來解決這一問題,如使用 **Zookeeper** 。由 *Zookeeper* 來決定鏈的組成,決定哪個節點是頭、尾,並監控哪個節點出了故障。當發生網路故障時,由 *Zookeeper* 來決定鏈的新組成,而不是基於各節點對於網路情況的自身感知