十年技術大牛總結:分布式架構之日誌技術

2019-07-06     IT技術分享

實際工程中NWR是寬鬆模式,中心節點(第三方zookeeper)讀取R個副本,選擇R個副本中 版本號最高 的為新的primary。還可以利用paxos等協議選出新的primary,每個節點以自己的版本號 發起paxos提議 ,選出的新primary是某個超過半數副本中版本號最大的副本 。

當機器宕機的時候,我們需要如何去恢復宕機之前那些數據? 日誌技術 是宕機恢復的主要技術之一。日誌技術最初使用在資料庫系統中。嚴格來說日誌技術不是一種分布式系統的技術,但在分布式系統的實踐中,卻廣泛使用了日誌技術做宕機恢復,甚至如BigTable等系統將日誌保存到一個分布式系統中進一步增強了系統容錯能力。

先簡單介紹資料庫系統中的日誌技術,抽象簡化問題模式,在簡化模型的基礎上介紹兩種實用的日誌技術 Redo Log 與 No Redo/ No Undo Log 。

資料庫系統日誌技術簡述

在資料庫系統中實現 宕機恢復 ,其難點在於資料庫操作需要滿足ACID,尤其在支持事務的資料庫系統中宕機往往發生在某些事務只執行了部分操作的時候。此時宕機恢復的主要目標就是資料庫系統恢復到一個穩定可靠狀態,消除未完成的事物對資料庫狀態的影響。

資料庫日誌主要分為Undo Log、Redo Log、Redo/Undo Log與No Redo/ No Undo Log。這四類日誌的區別在更新日誌文件和數據文件的時間點要求不同,從而造成性能和效率也不相同。可以參考有關資料庫系統方面的資料去深入了解這四類日誌技術 。

Redo Log與Check point

問題模型 :首先簡化原資料庫系統中的問題模型為一個較為簡單的模型:假設需要涉及一個高速的單機查詢系統,將數據全部存放在內存中以實現高速的數據查詢,每次更新操作更新一小部分數據(列如key-value中的某一個key)。現在問題為利用日誌技術實現該內存查詢系統的宕機恢復。與資料庫的事務不同的是,這個問題模型中的每個成功的更新操作都會生效。也等效為資料庫的每個事務只有一個更新操作,且每次更新操作都可以也必須立即提交。

Redo Log :Redo Log是一種非常簡單實用的日誌技術。在上面的問題模型中,只需按照如下流程更新既可以使用 Redo Log 。

Redo Log更新流程

  1. 將 更新操作的結果 (例如set k1=1,則記錄k1=1)以追加(append)的方式寫入磁碟日誌文件
  2. 按更新操作修改內存中的數據
  3. 返回更新成功

上述更新流程中第2步如果沒有考慮修改內存數據需要多線程互斥等問題,對於說明Redo Log的原理沒有影響。

從Redo Log的流程可以看出,Redo寫入日誌的內容是更新操作完成後的結果(這點是與Undo Log的區別之一),由於是 順序追加日誌 文件,在磁碟等對 順序寫 有力的存儲設備上效率較高。

用Redo Log進行宕機恢復非常簡單,只需要」 回放 」日誌即可。

Redo Log的宕機恢復

  1. 從頭讀取日誌文件中的每次更新操作的結果,用這些結果修改內存中的數據。

從Redo Log的宕機恢複流程也可以看出,只有寫入日誌文件的更新結果才能在宕機後恢復。這也是為什麼在Redo Log流程中需要先更新日誌文件再更新內存中的數據的原因。假如先更新內存中的數據,那麼用戶立刻就能讀到更新後的數據,一旦在完成內存修改與寫入日誌直接發生宕機,那麼最後一次更新操作無法恢復,但之前與困難已經讀取到了更新後的數據,從而引起不一致的問題。

Check point

宕機恢複流量的缺點是需要回放所有redo日誌,效率較低,假如需要恢復的操作非常多,那麼這個宕機恢復過程將非常漫長。解決這一問題的方法引入了check point技術。在簡化的模型下,check point技術的過程即將內存中的數據以某種易於重新加載的數據組織方式完整的dump到磁碟,從而減少宕機恢復時需要回放的日誌數據。

check point流程

  1. 向日誌文件中記錄「begin check point」
  2. 將內存中的數據以某種易於重新加載的數據組織方式dump到磁碟上
  3. 像日誌文件中記錄「end check point」

在check point流程中,數據可以繼續按照Redo Log更新流程走,這段過程中新更新的數據可以dump到磁碟也可以不dump到磁碟,具體取決於實現。例如,check point開始時k1=v1,check point過程中某次更新為k1=v2,那麼dump到磁碟上的k1的值可以是v1也可以是v2。

check point的宕機恢復

  1. 將dump到磁碟的數據加載到內存
  2. 從後向前掃描日誌文件,尋找最後一個「end check point」日誌
  3. 從最後一個「end check point」日誌向前找到最近的一個「begin check point」日誌,並回放該日誌之後的所有更新操作日誌

上述的check point的方式依賴redo日誌中記錄的都是更新後的數據結果這一特徵,即使dump的數據已經包含了某些操作的結果,重新回放這些操作的日誌也不會造成數據錯誤。同一條日誌可以重複回放的操作即所謂具有」 冪等性 」的操作。工程中,有些時候Redo日誌無法具有冪等性,例如 加法操作、append操作 等。此時,dump的內存數據一定不能包括「begin check point」日誌之後的操作。為此,有兩種方法,其一是checkpoint的過程中停更新服務,不能進行新的操作,另一種方法是,設計一種支持快照(snapshot)的內存數據結構,可以快速的將內存生成快照,然後寫入check point日誌再dump快照數據。至於如何設計支持快照的內存數據結構,方式也很多,例如假設內存數據結構維護key-value值,那麼可以使用哈希表數據結構,當做快照時,新建一個哈希表接收新的更新,原哈希表用於dump數據,此時內存存在兩個哈希表,查詢數據時查詢兩個哈希表併合並結果 。

No Undo/ No Redo Log

介紹另一種特殊的日誌技術「No Undo/ No Redo Log」,這種技術也稱之為「0/1目錄」(0/1 directory) 假設另一種問題場景:若數據維護在磁碟中,某批更新由若干個更新操作組成,這些更新操作需要 原子生效 ,即要麼同時生效,要麼都不生效。


0/1目錄技術中有兩個目錄結構,稱為目錄0和目錄1。另有一個結構稱為主記錄(master record)記錄當前正在使用的目錄稱為活動目錄。主記錄中要麼記錄使用目錄0,要麼記錄使用目錄1。目錄0或者目錄1記錄了各個數據在日誌文件中的位置。

圖中給出了一個0/1目錄的例子。活動目錄為目錄1,數據有A、B、C三項。查目錄1可得A、B、C三項的值分別為2、5、2。0/1目錄的數據更新過程始終在非活動目錄上進行,只是在數據生效前。將主記錄中的0、1值反轉,從而切換主記錄。

0/1目錄數據更新流程

  1. 將活動目錄完整拷貝到非活動目錄
  2. 對於每個更新操縱,新建一個日誌項記錄操作後的值,並在非活動目錄中將相應數據的位置修改為新建的日誌項的位置
  3. 原子性修改主記錄: 反轉主記錄中的值,使得非活動目錄生效

0/1目錄的更新流程很簡單,通過0、1目錄的主記錄切換使得一批修改的生效是原子的。

0/1目錄將批量事務操作的原子性通過目錄手段歸結到主記錄的原子切換。 由於多條記錄的原子修改一般較難實現而單條記錄的原子修改往往可以實現,從而降低了問題實現的難度。 在工程中0/1目錄思想運用非常廣泛,其形式也不局限在上面的流程中,可以是內存中兩個數據結構的來回切換,也可以是磁碟上的兩個文件目錄的來回生效切換 。

工程投影

日誌技術的使用非常廣泛,在zookeeper系統中,為了實現高效的塑膠訪問,數據完全保存在內存中,但更新操作的日誌不斷持久化到磁碟,另一方面,為了實現較快速的宕機恢復,zookeeper周期性的將內存數據以checkpoint的方式dump到磁碟。

MySQL的主從庫設計也是基於日誌。從庫只需通過回放主庫的日誌,就可以實現與主庫的同步。由於從庫同步的速度與主庫更新的速度沒有強約束,這種方式只能實現 最終一致性 。

需要的Java架構師方面的資料可以關注之後私信哈,回復「資料」領取免費架構視頻資料,記得要點贊轉發噢!!

文章來源: https://twgreatdaily.com/zh-tw/Gc0SR20BJleJMoPMit2t.html