副本機制與副本同步------《Designing Data-Intensive Applications》讀書筆記6

来源:https://www.cnblogs.com/happenlee/archive/2018/01/19/8316069.html
-Advertisement-
Play Games

進入到第五章了,來到了分散式系統之中最核心與複雜的內容: 副本與一致性 。通常分散式系統會通過網路連接的多台機器上保存相同數據的副本,所以在本篇之中,我們來展開看看如何去管理和維護這些副本,以及這個過程之中會遇到的各種問題。 1.副本 在數據系統之中,我們通常會有這樣幾個原因來使用副本技術: 保持地 ...


進入到第五章了,來到了分散式系統之中最核心與複雜的內容:副本與一致性。通常分散式系統會通過網路連接的多台機器上保存相同數據的副本,所以在本篇之中,我們來展開看看如何去管理和維護這些副本,以及這個過程之中會遇到的各種問題。

1.副本

在數據系統之中,我們通常會有這樣幾個原因來使用副本技術:

  • 保持地理位置接近用戶,從而減少延遲(如:Cache,CDN技術
  • 提高系統的可用性和魯棒性,即使系統中的某些部分已經失效了,仍然可以對外提供服務。(如:GFS三副本的設計
  • 通過擴展性來提供讀查詢,從而增加讀取吞吐量。(如:ZooKeeper之中的Observer

首先,如果副本的數據不隨時間變化,那麼副本的管理是比較簡單的:只需要將數據複製到每個節點一次,就OK了。副本管理真正的困難在於對副本數據的修改,這會涉及到很多瑣碎的問題。其次,副本複製時要考慮許多權衡,使用同步還是非同步複製,以及如何處理失效的副本?接下來我們來一一探討這個問題。

2.Leader-Follower機制

如何保障多個副本在不同節點上的一致性一直分散式系統之中的一個核心問題。分散式系統在寫入數據時,需要由每個副本進行處理;否則,副本將不再包含相同的數據。Leader-Follower是一種常見的機制,我們來梳理一下它的原理:

    1. 一個節點上的副本被指定為Leader。當客戶端需要向系統寫入數據時,必須將寫入請求發送給Leader,由Leader首先將新數據寫入本地存儲的副本。
    1. 管理其他副本的節點稱為Follower。每當Leader將新數據寫入本地存儲d的副本時,也會將數據更改寫入日誌之中。每個Follower會從Leader那裡獲取修改日誌,並相應地更新數據到的本地副本之中,這樣,所有的在Follower上副本的修改順序會和Leader保持相同的順序。
    1. 當客戶端需要從系統之中讀取數據時,它可以查詢Leader或其他Follower。(註:Follower與Leader之中的數據存在延遲,無法保證強一致性)寫入請求只能由Leader來響應,或是由Follower轉發給Leader

Leader-Follower機制

許多關係資料庫在同步副本時使用這樣的機制,如PostgreSQL,MySQL,Oracle Data Guard 和SQL Server。同時許多非關係型資料庫與分散式消息隊列也採用這樣的機制,包括MongoDB,Rethinkd,Kafka,RabbitMQ。

2.1 同步與非同步複製

在副本進行主從複製時一個重要細節是複製是同步還是非同步發生的?(在關係資料庫中,這往往是一個可配置的選項。在其他系統之中,如Ceph,是系統預設的)

同步複製與非同步複製的響應時間的比較

由上圖可知,同步複製有相當大的延遲,而非同步複製的響應相當快速。但是非同步複製卻不能保證完成所需要多長時間。有些情況下,Follower的數據可能比Leader上的數據落後幾分鐘或更多。如:節點之間存在網路問題或節點的故障恢復。如果Leader失敗且不可恢復,則尚未複製到Follower的任何寫操作都將丟失。

而同步複製的優點是保證了Follower與Leader之間的副本一致性,一旦任意一個Leader失效了,任何一個Follower的數據都與Leader相同。但是同步複製一旦出現網路或節點的故障,會導致無法處理寫入。Leader必須阻止所有寫入並等待Follow上的副本再次可用。如果所有的Follower都是同步複製,那麼任何一個節點的中斷都會導致整個系統癱瘓。在實際運用之中,如果在資料庫上啟用同步複製,通常其中一個副本是同步複製的,而另一個是非同步複製的。如果同步的副本變得不可用或十分緩慢,可以將同步操作切換到另一個非同步副本之中。這樣保證了至少兩個節點上有一個數據的最新副本:Leader和一個同步Follower。這種配置稱之為半同步。(鏈式複製也是類似於半同步的一種複製機制,不丟失數據但仍能提供良好性能和可用性的複製方法。)

2.2 添加新的Follower

有時我們需要添加新的Follower來增加副本的數量,或者替換失敗的節點。此時就需要確保新的Follower擁有一個正確的副本的數據。僅僅將數據文件從一個節點複製到另一個節點通常是不夠的:客戶端不停向系統寫入數據,所以數據副本總是處於不斷變化的狀態。這裡可以簡單地通過鎖定系統,使其拒絕客戶端的寫請求來使各個副本上保持一致,但這樣會大大降低系統的可用性。所以我們需要一個不停機的方式來添加新的Follower:

  • 1.在某個時間點對Leader的副本進行快照,並且將快照複製到新加入的Follower節點。

  • 2 .Follower連接到Leader,並向Leader請求快照之後所有的數據更改。通常是Leader節點的日誌序列號。

    1. 當Follower處理完快照之後的數據更改之後,它就可以正常處理來自Leader的數據更改了。
2.3 節點故障

在分散式系統之中,任何節點都可能出現故障,而能夠在不停機的情況下重新啟動單個節點是操作和維護是十分必要的。儘管每個節點故障,但我們需要讓一個節點停機的影響儘可能小。

  • Follower故障

在Follower的本地磁碟上,都保存著從Leader收到的數據更改的日誌。當一個Follower崩潰並重新啟動,或者Leader與Follower之間的網路暫時中斷。Follower可從它的日誌找到故障發生之前處理的最後一個事務,然後連接到Leader並請求在Follower斷開連接的時候發生的所有數據變化。(這個流程和添加新的Follower其實是同樣的思路

  • Leader故障

在處理Leader的失敗時顯然會更為棘手:其中一個Follower需要被提升為新的Leader,客戶端也需要識別並且將後續的請求發送給新的Leader,而其他的Follower則需要開始在新Leader之下工作。處理Leader故障通常是如下的流程:

  • 1、確認Leader失效。絕大多數系統使用超時機制:如果一個節點不響應一段時間,例如,30秒,它被認為是失效了。(如果是中心化的系統可以採用Lease機制。筆者在碩士生階段對Cassandra資料庫有過系統的調研,在Cassandra中採用了由日本學者Naohiro Hayashibara提出的《The Phi Accrual Failure Detector》失敗探測演算法,通過多維度累積量來判斷節點是否失效,不失為一個好的解決方案,十分適合類P2P架構的分散式系統

  • 2、選取新的Leader。在中心化架構之中,如HDFS,新的Leader可以用中心化節點指定。而在非中心化的架構之中,則可以通過選舉過程來完成,分散式系統之中的選舉協議有很多:2PC,3PC,Paxos,Raft等等。

  • 3、調整系統配置以使用新的Leader。如果舊的Leader回歸到集群,它可能仍然認為自己是Leader,這時需要確保舊的Leader成為Follower並承認新的Leader。

如果是非同步複製的場景,新的Leader可能舊的Leader之前的完整的寫入信息。最常見的解決方案是丟棄舊Leader之前寫入多於新Leader的信息丟棄,但是這顯然違反了數據系統寫入持久性的要求。
在某些故障場景中,可能會出現兩個節點都認為他們是Leader,這種情況被稱為腦裂。此時兩個Leader都會接受寫請求,數據很可能會出現丟失或損壞。
什麼時候進行故障切換也是一個值得探討的問題:較長的超時時間意味著在Leader失效的情況下恢復時間更長。然而,如果時間太短,可能會有不必要的故障轉移。例如,臨時負載高峰時刻可能導致節點的響應時間增加到超時,那麼不必要的故障轉移會使情況變得更糟,而不是更好。為此,一些運營團隊更願意執行手動的故障轉移,即使系統本身支持自動的故障轉移。

3. 日誌的複製

日誌在副本的一致性之中是至關重要的,所以我們接下來簡要的梳理一下日誌複製可用的方法:

  • Statement-Based複製
    在最簡單的情況下,Leader將每個寫請求通過日誌的形式發送給Follower。每個Follower解析和執行對應的操作語句,雖然這聽起來很合理,但是實際操作中會存在一些坑:

(1) 非確定性函數,如now()獲得當前的日期和時間或rand()得到一個隨機數,這樣會導致副本之間的不一致。(這裡可以轉換思維,用一個確定的修改值,來替換不確定性的函數調用)

(2) 如果使用一個自動遞增的列,或如果他們依賴於資料庫中的現有數據(例如,更新…在<條件>),他們必須執行完全相同的順序在每個副本,否則也會產生不一致性。(非同步轉發,亂序到達。這個可以通過操作序列號等強制要求進行規避。

(3) 有副作用的語句(例如觸發器、存儲過程、用戶定義函數)可能會導致每個副本上出現不同的副作用。

  • Write-ahead日誌複製
    日誌是一個只包含所有寫入操作的位元組序列。我們可以使用完全相同的日誌來在另一個節點上構建一個副本。Leader將日誌寫入磁碟之後,將它通過網路發送給Follower。當Follower處理這個日誌時,它構建了一個與Leader完全相同的數據結構的副本。這種方式的缺點是:日誌在非常低的級別上描述數據。這使得數據拷貝與存儲引擎緊密耦合。

  • Row-based日誌複製
    Row-based與Write-ahead的方法類似,但是它允許複製日誌與存儲引擎內部分離。這種日誌稱為邏輯日誌,邏輯日誌通常是描述在一個行的粒度上記錄寫入操作:
    對於插入的行,日誌包含所有列的新值。
    對於已刪除的行,日誌包含足夠的信息以唯一地標識刪除的行。(主鍵
    對於更新的行,日誌包含足夠的信息以唯一地標識更新的行,以及所有列的新值。
    由於邏輯日誌與存儲引擎內部分離,因此可以更容易地保持向後相容,從而允許Leader與Follower運行不同版本的數據系統,甚至是不同的存儲引擎。同時,邏輯日誌格式對外部應用程式也更容易解析。可以將邏輯日誌的內容發送到外部系統(如用於離線分析的數據倉庫),或者用於構建自定義索引和緩存。

4. 複製延遲

副本可以增加系統的可伸縮性(處理比單個機器處理更多的請求)和降低延遲(將副本放置在離用戶更近的地方)。寫入操作必須通過Leader副本,但是只讀查詢可以在任何副本上進行。 對於一次寫入,多次讀取的應用來說,採用讀擴展架構是十分合理的。但是由於上文提及的原因,我們通常不會採用同步複製的方式。這將導致數據出現明顯的不一致性:如果您同時對Leader和Follwer執行相同的查詢,可能會得到不同的結果,因為並不是所有的寫入實時在Follower上反饋。這種不一致性僅僅是暫時狀態,所以這種情況被稱為最終一致性。

對於這種情況我們應該這麼去處理和理解,我們下回分解~~~(第五章的內容炒雞多,接下來會通過多篇讀書筆記來給大家梳理,講解,下一篇再見~~


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 偽元素和偽類之所以這麼容易混淆,是因為他們的效果類似而且寫法相仿,但實際上 css3 為了區分兩者,已經明確規定了偽類用一個冒號來表示,而偽元素則用兩個冒號來表示。 :Pseudo-classes ::Pseudo-elements 但因為相容性的問題,所以現在大部分還是統一的單冒號,但是拋開相容性 ...
  • 預設字體大小是16px 在<html>中設置字體大小 與em的區別: em是在父級設置字體大小受影響 移動端適配 首先獲取屏幕的寬度 計算當前屏幕寬度和640的比例 計算出font-size的值 改變html的font-size的值 <!DOCTYPE html> <html lang="en" s ...
  • 在我們程式員的日常開發中,總會時不時的需要用到地圖開發,我也在多次碰到之後,寫下我對地圖開發的理解經驗和總結。 一、地圖的選擇 回想一下我們生活中用到的地圖工具,數了一下,百度地圖,高德地圖,騰訊地圖,谷歌地圖,其他。 1、作為開發者,我們應該選擇普遍被大眾認可的地圖平臺,所以其他這個選項中,除去最 ...
  • // 全圖預設背景 // backgroundColor: ‘rgba(0,0,0,0)’, // 預設色板 color: ['#ff7f50','#87cefa','#da70d6','#32cd32','#6495ed', '#ff69b4','#ba55d3','#cd5c5c','#ffa5 ...
  • 原地址:http://blog.csdn.net/she_lover/article/details/51448967theme = { // 全圖預設背景 // backgroundColor: ‘rgba(0,0,0,0)’, // 預設色板 color: ['#ff7f50','#87cefa ...
  • 在使用`React Native`開發中,我們熟練的採用`JavaScript`的方式發送請求的方式發送一個請求到服務端,但是處理這個請求的過程其實和處理`Web`應用中發送的請求的過程是不一樣的。因為處理這個請求的目標不是瀏覽器,而是嵌入這個應用的原生操作系統。 ![banner](https... ...
  • <!doctype html><html><head><meta charset="utf-8"><title>無標題文檔</title></head><style>#div1{position:relative;}#div1 div{width:50px;height:50px;position: ...
  • Simple Demo 假設我有一部iPhoneX,又非常喜歡玩游戲,那麼我這部破手機主要存在兩種狀態:待機和游戲中。 此時手機的狀態圖非常簡單: 將這個狀態圖轉換為代碼: 每一個狀態用不同的整數代表,將每一個動作整合成方法,每一個動作都可能造成狀態的轉換。 測試代碼: 更改需求 但存在一種特殊情況 ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...