「分散式技術專題」時鐘系列一:事件的因果和邏輯時鐘

Hubble資料庫發表於2023-02-13

隨著資料量的上升,傳統單機架構存在的瓶頸已不能滿足對效能和容量的要求,從而分散式系統變得越來越火熱,但另一方面, 分散式也帶來了很多相對於單機架構不同的問題。其中一個問題就是多節點的時間同步問題:不同節點上的物理時鐘難以同步,導致無法區分在分散式系統中多個節點的事件順序。

早在 1978年,Lamport在《Time, Clocks and the Ordering of Events in a Distributed System》中,就提出了邏輯時鐘的概念,就是用來解決分散式系統中事件發生的順序問題。

事件的因果

“Time is an illusion.”愛因斯坦如是說。

邏輯時鐘是 Lamport在1978年提出的一種在分散式系統中對事件進行時間戳排序的方法,在其中定義了因果關係,稱為before。

例如, before在航班滿員,航班可預訂。這裡“事件預訂”before“航班滿員”,預訂和滿員就形成了因果關係。

現實世界中,確定事件預訂發生在事件滿員之前,需要預訂發生在比滿員更早的時間。因果關係是一個事件(因)和第二個事件(果)之間的作用關係, 其中後一個事件被認為是前一個事件的結果。一般來說,一個事件是很多原因綜合產生的結果, 而且原因都發生在較早的時間點。

而在分散式系統中,有時不可能說兩個事件中的一個首先發生。關係 “happened before”只是系統中事件的部分排序。

部分排序

在分散式系統中,事件 A發生在事件B之前,如果A發生在比B更早的時間,需要系統正確的滿足規範。如果分散式系統以物理時間為單位,可能存在時鐘不完全準確,沒辦法保持精確的物理時間的問題。因此,在邏輯時鐘論文裡,定義了“before”關係,而不使用物理時鐘。

“before”標記為=>,需要滿足三個條件:

1.  如果 a和b是同一程式中發生的事件,且a先於b,則a->b

2.  如果 a是一個程式中的傳送訊息,b是另一個程式中接收此訊息,那麼a->b

3.  如果 a->b並且b->c,那麼a->c。兩個事件是併發的,如果a≠>b和b≠>a

對於任意事件 a,定義a≠>a。

另一種說法是 a->b意味著事件a是事件b的因。兩個事件併發說明二者不能發生因果影響, 兩個事件相互獨立。這就意味著部分排序。

這樣,在分散式系統中,事件的順序可以根據傳送的訊息來定義,只考慮實際傳送的訊息。

邏輯時鐘

由部分排序可知,問題的關鍵點在於節點間的互動要在事件發生順序上達成一致, 而不是對於時間達成一致。所以,邏輯時鐘指的是分散式系統中用於區分時間發生順序的機制。從某種意義上來講,現實世界的物理時間其實是邏輯時鐘的特例。

分散式系統中,按是否存在節點互動可分為三類事件,節點內部,傳送事件,接收事件。

Lamport邏輯時鐘的原理如下:

1.  每個事件對應一個 Lamport時間戳,初始值為0.

2.  如果事件發生在節點內部,本地程式中的時間戳加 1.

3.  如果事件是傳送事件,本地程式中的時間戳加 1並在訊息中帶上該時間戳

4.  如果事件屬於接收事件,本地程式中的時間戳 = Max(本地時間戳,訊息中的時間戳) + 1

下面詳細說明邏輯時鐘的原理。

單機多程式程式可以由鎖進行同步,因為這些程式都執行在作業系統上, 可以由作業系統為它們進行排序,作業系統知道所有需要同步程式的所有資訊。但是在分散式系統中,各個程式執行在各個節點上, 那麼分散式系統中多程式怎麼進行同步呢?

把邏輯時鐘引入到系統中,由一個抽象觀點開始,在這個觀點中時鐘只是給事件分配數字的一種方式, 其中這個數字就是事件發生的時間。給每個程式 Pi分配時鐘Ci,時鐘Ci是一個函式,負責分配數字, 例如為事件a分配時鐘為Ci(a)。系統時間函式C為任意事件b分配時間C(b)=Cj(b),如果b是發生在程式Pj下。這裡的時鐘是邏輯時鐘不是物理時鐘,C函式可以是與物理時鐘無關的計數器實現。

這裡由於論文時間較早,所以都是以執行緒為例,可以推廣到分散式節點。

邏輯時鐘的定義必須基於事件發生的順序而不是物理時鐘。如果事件 a發生在事件b之前, 那麼a應該發生在b的更早時間。表述如下:如果a->b,那麼C(a)<C(b)。這裡注意, 相反條件不一定能成立,因為這將意味著任何併發都必須同時發生。

logic_clock1
如圖 1,這裡p1,p2,p3都與q3併發,這意味著它們都和q3同一時間發生,但這與時間條件相矛盾, 因為p2->p3。

對關係的定義中很容易看出,如果以下兩個條件成立,則時鐘條件是滿足的。
• 條件1,如果a和b都是程式Pi中的事件,並且a->b,那麼Ci(a)<Ci(b).
• 條件2,如果a是Pi傳送一個訊息的事件,b是Pj中接收這個訊息的事件,那麼Ci(a)<Cj(b)

考慮時空圖,假設一個程式時鐘 ticks分配數字,發生在程式事件之間。例如a和b是Pi的連續事件,Ci(a)=4,Ci(b)=7,時鐘心跳5,6,7發生在兩個事件之間。這樣可以在不同程式的所有相似的ticks之間畫一條虛線形成圖1空間圖,如圖2。

logic_clock1
條件 1意味著同一程式上的任意事件之間必須要虛線,條件2意味著圖中每個訊息線都要跨越虛線。從圖中可以看出為什麼這兩個條件是時鐘條件。

程式 Pi的時鐘用Ci表示,Ci(a)表示事件a的時鐘。事件之間Ci的值會變化,改變Ci本身並不構成事件。

為了確保滿足時鐘條件 1,2,需要遵守以下實現規則:
• IR1. 每個程式Pi在兩個連續事件之間遞增Ci.
• IR2. (a)如果a是程式Pi傳送訊息m的事件,則訊息m包含時間戳Tm=Ci(a)
• IR2. (b)在收到訊息m時,處理Pj設定Cj大於或等於現在Tm的值

進行全域性事件排序,可以使用滿足時鐘條件的時鐘系統在所有系統事件的集合上進行總排序。
能夠對事件進行完全排序,對於實現分散式系統非常有用。實現一個正確的邏輯時鐘系統就是為了獲得這樣的總排序。考慮共享資源的程式或節點固定的集合組成的系統,一次只能有一個程式或者節點使用資源, 因此程式必須同步自己,以避免發生衝突。

論文提到解決這一問題要滿足三個條件:
1. 已被授予資源的程式必須先將其釋放,然後才能將其授予另一個程式。
2.   對資源的不同請求必須按請求的順序授予。
3. 如果每個被授予資源的程式最終都會釋放,那麼每個請求最終都會被接受。

為解決這些問題,並實現一個滿足條件的時鐘系統,滿足規則 IR1和IR2。定義一個=>用來給全部事件排序。有了這個順序,找到一個解決方案就變得簡單了, 它只涉及確保每個程式或節點知道所有其他程式或節點的操作了。

為了簡化問題,進行一些不是必須的假設,這些假設的引入是為了避免分散實現細節。假設對於兩個程式 Pi和Pj,從Pi傳送到Pj的訊息時以相同的順序接收的。此外,我們假設每個訊息最終都被接收。並且假設一個程式可以直接向每個其他程式傳送訊息。
每個程式都維護自己的請求佇列,這是任何其他程式都看不到的。假設請求佇列最初包含單個訊息 T0:P0請求資源,其中P0是最初授予資源的程式, T0小於任何時鐘的初始值。

透過五條規則定義演算法,為了方便起見,假設每個規則定義的操作形成單個事件。

1.  要請求資源,程式 Pi傳送訊息Tm:Pi請求給每個其他程式,並將該訊息放到其請求佇列中, 其中Tm是訊息的時間戳。

2.  每個程式 Pj接收請求資源訊息Tm:Pi,它將其放置在請求佇列中,並向Pi傳送一個帶有時間戳的確認訊息。

3.  為了釋放資源,程式 Pi從其請求佇列中刪除Tm:Pi請求西苑訊息,並且傳送Pi時間戳釋放資源訊息到其他程式。

4.  當程式 Pj接收一個Pi釋放資源訊息時,它從其請求佇列中刪除任一Tm:Pi請求資源。

5.  當滿足以下兩個條件時,程式 Pi被賦予資源:(1)在其佇列中由一個Tm:Pi訊息,它在佇列中 =>其他請求。(為了定義=>,我們定義一個訊息,使用傳送訊息的事件來識別。)

Pi收到比Tm更晚的每一個其他程式的訊息。
可以很容易的看到演算法滿足條件 1 - 3
舉例說明,假設有 3個程式,根據演算法說明,初始化狀態各個程式佇列裡面都是(0,0)狀態, 此時鎖屬於P0。

logic_clock3
接著 P1會傳送請求資源的訊息給所有其他程式,並且放到自己的請求佇列裡面, 根據演算法,P1的時鐘計數變為1,而接受訊息的P0和P2的時鐘為訊息時間戳+1。

logic_clock4
收到 P1的請求之後,P0和P2要傳送確認訊息給P1表示自己已經收到了。由於目前請求佇列裡面第一個不是P1發出的請求,所以此時鎖仍屬於P0。但是由於收到了確認訊息,此時P1已經滿足了獲取資源的第一個條件:P1已經收到了其他所有程式時間戳大於1的訊息。

logic_clock5
假設 P0此時釋放了鎖,傳送釋放資源的訊息給P1和P2,P1和P2收到訊息後把請求(0,0) 從佇列中刪除。

logic_clock6
P0釋放了資源之後,P1滿足了獲取資源的兩個條件,它 的請求在佇列最前面和 P1 已經收到了其他所有程式時間戳大於1的訊息。也就是此時P1獲得了鎖。

總結

在邏輯時鐘的論文中描述的演算法大致就像上面描述的一樣,但顯而易見,這個演算法並不是容錯的,只要有一個程式掛了或者響應很慢,都會影響到整個分散式系統。

但邏輯時鐘的思路就如上面描述的那樣,是整個分散式一致性演算法的基石, 所有的分散式一致性演算法都有邏輯時鐘的影子在內。邏輯時鐘定義了分散式系統裡面的時間概念,解決了分散式系統中區分時間發生的時序問題。

實際上後續產生的向量時鐘、全域性時鐘亦或者混合時鐘,都是對邏輯時鐘的增強, 其基礎都是邏輯時鐘。

 

以上為事件的因果和邏輯時鐘,「分散式技術專題」是國產資料庫 hubble 團隊精心整編,專題會持續更新,歡迎大家保持關注。

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70026685/viewspace-2935011/,如需轉載,請註明出處,否則將追究法律責任。

相關文章