在使用分佈式數據庫的時候,不一樣節點中數據的一致性一貫是一個經典且難以解決的問題,而這個問題的根源是難以實現一個全局統一的時鐘。下面就描述了這種問題的一種狀況:算法
如上圖所示:A,B,C 表示分佈式系統中的三個數據庫,縱軸表示時間。在 TA1 時刻 A 作出了更改 Key=Value1
,此次更改在 TC2 時刻傳輸到了 C;在 TB1 時刻 B 作出了更改 Key=Value2
,此次更改在 TC1 時刻傳輸到了 C。那麼問題來了:C 數據庫中的 Key
應該等於 Value1
仍是 Value2
呢?數據庫
天然地,咱們能夠想到:Key
的取值應該和最新的更改保持一致。可是,因爲很難實現一個全部節點都一致的全局時鐘,因此不一樣節點各自的時鐘實際上並不具備可比性,即 TA1 < TB1 也不能說明 B 對 Key
的更改是在 A 以後發生的。分佈式
接下來要介紹的向量時鐘算法
就可以部分解決上面的問題。ui
在一個有 N 個節點的分佈式數據庫中,用一個 N 維的向量來表徵時間,其中的某一個維表示一個節點的時間,這個時間向量按照如下規則進行處理:spa
全部節點的初始時間向量都是0;3d
每一次經歷一個時間間隔,都要在各自的時間維度上加1;code
每次發送數據,都要將這個向量時間做爲時間戳和數據一塊兒發出去;blog
每次節點收到了時間向量,都要比較該時間向量和自身時間向量,並取二者中每一維中的最大值,做爲自身新的時間向量;事件
當收到有衝突的更改時,比較這兩次更改的時間向量:若存在偏序關係,則取偏序關係中時間向量較大的對應的值,並以此做爲本節點新的時間向量;若不存在偏序關係,則不能合併;圖片
其中的偏序關係是指:若A向量中的每一維都大於等於B向量,那麼就說A,B向量之間存在偏序關係,不然不存在偏序關係
。
舉個例子:
A,B,C 三個節點的初始時間向量都是 (0,0,0)
,該向量的一,二,三維分別對應 A,B,C 三個節點各自的時間。
A 做出更改 Key=Value1
,時間向量變爲 (1,0,0)
;
A 的更改傳輸到了 B 處,B 處 Key=Value1
, 且時間向量變爲 (1,0,0)
;
B 做出更改 Key=Value2
, 將時間向量中本身對應的那一維加 1 變爲 (1,1,0)
;
B 和 A 的更改都同步到了 C 處。C 比較二者的時間向量 (1,0,0)
和 (1,1,0)
,發現存在偏序關係,因而 C 的時間向量更新爲 (1,1,0)
且 Key=Value2
;
雖然咱們已經學會了怎麼使用時鐘向量算法,可是彷佛還和算法的本質隔着一層霧:咱們其實並無解決「不一樣節點之間統一的時鐘」這一個客觀的問題,可是經過向量時鐘算法,咱們卻能夠肯定一些更改的前後順序,而這些是在以前沒法肯定。那多出來的信息是從哪裏得到的?
結合前面給出的兩張圖中的兩個例子,對比傳統的方法和時間向量算法的差別:
其實客觀上是能夠得知 B 對 Key
的更改是在 A 以後的,由於 B 是在收到 A 的更改以後才進行的下一步更改。傳統的方法丟失了這部分信息,而向量時鐘算法將這個信息保存了起來,用於後面對更改的前後順序的斷定。用數學表達就是:
由於 TB0 > TA1, TB1 > TB0,因此 TB1 > TA1;而傳統的方法丟失了「TB1 > TB0」這條信息。
那麼,既然向量時鐘的惟一目的是傳輸「TB1 > TB0」這條信息,那麼其餘任何方法,只要可以將這類信息包含進去,也擁有和向量時鐘算法相同的效果。好比 Git
中衝突合併的思想和向量時鐘算法的本質實際上是同樣的:Git
中不一樣的本地倉庫擁有不一樣的時間維度,每一次 commit
對應一個時間維度上值的增長,能夠快速合併的兩個倉庫對應的時間向量是具備偏序關係的。
總結以下:
給不一樣的節點設置不一樣的時間維度
體現了 不一樣節點之間沒有一個統一的時鐘,所以不一樣節點之間的時間就不具備可比性
;
每一個節點的更新會在本身的時間維度上加 1
體現了 同一個節點上的時間是能夠比較的
;
時鐘向量 A,B 具備偏序關係且 A>B
體現了 A 是在同一節點上,在 B 的基礎上增長的獲得的;同一節點上發生的事件能夠判斷前後順序,那麼能夠得知 A 發生在 B 以後
;
時鐘向量 A,B 不具備偏序關係
體現了 A,B 之間不存在可以將某一個向量的尾端順着同一個節點連到另外一個向量中間的事件
;
因此向量時鐘算法的實質是:
將邏輯上能夠合併的衝突成功合併;
邏輯上沒法合併的衝突依舊衝突;
上面算法中的這種 不一樣節點中的時間不具備不具備可比性
和 用一個多維的時間來代替一維的時間
的時空觀,和狹義相對論中的時空觀很是相似。
在狹義相對論中,同一事件從不一樣的慣性參考系中觀察是不同的,而兩次事件能夠創建因果關係的前提是:兩個事件之間能夠用等於或小於光速的速度傳遞信息(或者說一事件位於另外一事件的光錐內部)。
聯繫:
在狹義相對論中的描述 | 在向量時鐘算法中的描述 |
不一樣的慣性參考系有不一樣的時間 | 不一樣的節點有不一樣的時鐘向量維度 |
兩件事件具備因果關係(事件 2 位於事件 1 的光錐內部) | 兩次更改可肯定前後順序(兩個向量具備偏序,相似光錐內部) |
兩件事件不具備因果關係(事件 2 位於事件 1 的光錐外部) | 兩件事件不具備因果關係(事件 2 位於事件 1 的光錐外部) |
更詳細的關於時鐘向量算法和狹義相對論時空觀的比較能夠閱讀參考文獻 3。
區別:
狹義相對論能夠用洛倫茲變換將不一樣的參考系中的時間進行變換(利用到不一樣參考系之間的相對速度),可是向量時鐘算法不能夠(其實邏輯上也能夠,可是實現後沒有現實意義),因此只能用多維的時間來表徵不一樣節點中的時間卻無法相互轉化。
Colin J. Fidge (February 1988)."Timestamps in Message-Passing Systems That Preserve the Partial Ordering". In K. Raymond (Ed.). Proc. of the 11th Australian Computer Science Conference (ACSC'88). pp. 56–66. Retrieved 2009-02-13.
Almeida, Paulo; Baquero, Carlos; Fonte, Victor (2008), "Interval Tree Clocks: A Logical Clock for Dynamic Systems", in Baker, Theodore P.; Bui, Alain; Tixeuil, Sébastien, Principles of Distributed Systems, Lecture Notes in Computer Science, 5401, Springer-Verlag, Lecture Notes in Computer Science, pp. 259–274, doi:10.1007/978-3-540-92221-6, ISBN 978-3-540-92220-9