Chandy-Lamport分布式快照算法
分析&回答
Distributed Snapshot
所謂分布式快照,實際上就是特定時間點記錄下來的分布式系統的全局狀態(global state)。分布式快照的主要用途有故障恢復(即檢查點)、死鎖檢測、垃圾收集等。
為了方便理解,我們仍然沿用原論文中的方法,將分布式系統抽象為一張有向圖:頂點稱為進程(process),邊稱為鏈路(channel)。下圖就示出包含3個進程和4個鏈路的分布式系統。
那么,全局狀態就要包含所有進程的狀態以及所有鏈路的狀態。由于進程之間在通過鏈路不停地交換數據,所以以下動作都可能造成全局狀態的改變:
- 進程p收到或發出一條消息M;
- 鏈路c承載了到達或離開進程p的一條消息M。
論文中將使分布式系統狀態發生變化的因素叫做事件(event),并給出了它的形式化定義,即e=<p, s, s’, M, c>。p、M、c的定義上面已經提到了,而s和s’分別是進程p在事件e發生之前及發生之后的狀態。
可見,進程對自己的狀態是有感知的,而鏈路本身只負責傳遞消息,它們的狀態不容易記錄。并且我們無法讓時間靜止,各個進程的時鐘也很有可能不同步,故不能在一瞬間同時捕獲所有進程和鏈路的狀態。所以必須要曲線救國,通過每個進程記錄的與自己相關的狀態合并出全局狀態,這也是Chandy-Lamport算法的核心思想所在。
下面具體介紹算法的細節。
The Chandy-Lamport Algorithm
Chandy-Lamport算法基于如下前提:在每對進程pi、pj之間都存在兩條單向的鏈路cij和cji,即對于pi來講,cij是出邊,cji是入邊。鏈路的網絡可靠,緩存無限大,并且先進先出,即鏈路上的消息會不重不漏地按序到達。
算法要達到如下的終極目標:
為了保證成功取得全局快照,Chandy-Lamport算法分為3個階段,即初始化快照、擴散快照與完成快照,并且借助一種與正常消息不同的特殊消息作為標記,英文稱為marker。這3個階段并沒有直接體現在論文中,而是出自普林斯頓大學相關課程的PPT,但算法實際流程則是嚴格一致的。下面敘述3個階段的流程。
Initiating a Snapshot
假設進程pi發起快照:
Propagating a Snapshot
對于任意一個進程pj(包含發起快照的那個進程),考慮它的所有入邊鏈路ckj。當在ckj上收到了marker消息時,有兩種情況。
- 如果pj還沒有記錄自己的狀態——
- 如果pj已經記錄過自己的狀態——
記下入邊鏈路上監聽到的消息,直到收到marker消息為止。
Terminating a Snapshot
若所有進程都成功地:
- 收到了marker消息;
- 記錄下了自己的狀態;
- 記錄下了入邊鏈路的狀態(就是鏈路上的消息)
則快照成功,算法流程結束。然后就可以將所有這些狀態傳輸到一個穩定的分布式存儲中心,全局快照就產生了。
Understanding the Algorithm
全局快照的難點在于,因為系統不能停止,每個進程向下游發送的消息是源源不斷的,所以必須得有個東西來劃分“當前的消息”與“將來的消息”,讓它們不會混淆,而marker消息就是這個界限。對進程pj的入邊鏈路ckj而言,如果收到的消息序列是[a, b, c, marker, d, e, f],那么就說明a/b/c三條消息屬于當前快照,而d/e/f三條消息屬于下一個快照。
另外,因為每個進程都記錄自己收到的消息,所以進程最終都能持有入邊鏈路的狀態。為什么要用接收進程來記錄?用兩句大白話來解釋:
- 只有發送了數據,下游才會(按序)接收到數據;
- 發送者無法知道數據在下游的接收情況。
如果不這樣設計,而采用簡單的單令牌系統的話,就會有問題。仍然借用論文中給出的一個例子:
進程p和q以令牌(token)的傳送來標定狀態,s1表示持有令牌,s0表示未持有令牌。假設在“token in C”全局狀態下保存快照,而q的時間戳比p早,那么就會造成兩個進程都處于s0狀態,而q認為令牌不在鏈路C中,p也認為令牌不在鏈路C’中,因此快照里令牌就會丟失,造成不一致。
Example
下面的圖示出有兩個進程的分布式系統根據Chandy-Lamport算法生成快照的過程,其中藍色的部分表示狀態已經被保存,并且進程P1發起快照。
反思&擴展
該算法是Flink Checkpoint機制原理核心算法。
為了大家更加方便的刷題,我們對文章進行了分類和整理,免費為大家提供刷題服務。程序員不欺騙程序員,趕緊掃碼小程序刷起來!
為了一站式解決面者刷題問題,部分內容可能存在摘錄情況,如有侵權辛苦您留言聯系我們,我們會刪除文章或添加引用文案,Thanks!
總結
以上是生活随笔為你收集整理的Chandy-Lamport分布式快照算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 并发编程-同步机制(一)
- 下一篇: 常见损失函数综述及区别