在使用分佈式數據庫的時候,不一樣節點中數據的一致性一貫是一個經典且難以解決的問題,而這個問題的根源是難以實現一個全局統一的時鐘。下面就描述了這種問題的一種狀況:mysql
如上圖所示: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 以後發生的。sql
接下來要介紹的向 量時鐘算法
就可以部分解決上面的問題。數據庫
在一個有 N 個節點的分佈式數據庫中,用一個 N 維的向量來表徵時間,其中的某一個維表示一個節點的時間,這個時間向量按照如下規則進行處理:分佈式
其中的偏序關係是指: 若A向量中的每一維都大於等於B向量,那麼就說A,B向量之間存在偏序關係,不然不存在偏序關係 。ui
舉個例子:spa
A,B,C 三個節點的初始時間向量都是 (0,0,0) ,該向量的一,二,三維分別對應 A,B,C 三個節點各自的時間。.net
雖然咱們已經學會了怎麼使用時鐘向量算法,可是彷佛還和算法的本質隔着一層霧:咱們其實並無解決「不一樣節點之間統一的時鐘」這一個客觀的問題,可是經過向量時鐘算法,咱們卻能夠肯定一些更改的前後順序,而這些是在以前沒法肯定。那多出來的信息是從哪裏得到的?code
結合前面給出的兩張圖中的兩個例子,對比傳統的方法和時間向量算法的差別:blog
其實客觀上是能夠得知 B 對 Key 的更改是在 A 以後的,由於 B 是在收到 A 的更改以後才進行的下一步更改。傳統的方法丟失了這部分信息,而向量時鐘算法將這個信息保存了起來,用於後面對更改的前後順序的斷定。用數學表達就是:
由於 TB0 > TA1, TB1 > TB0,因此 TB1 > TA1;而傳統的方法丟失了「TB1 > TB0」這條信息。
那麼,既然向量時鐘的惟一目的是傳輸「TB1 > TB0」這條信息,那麼其餘任何方法,只要可以將這類信息包含進去,也擁有和向量時鐘算法相同的效果。好比 Git 中衝突合併的思想和向量時鐘算法的本質實際上是同樣的: Git 中不一樣的本地倉庫擁有不一樣的時間維度,每一次 commit 對應一個時間維度上值的增長,能夠快速合併的兩個倉庫對應的時間向量是具備偏序關係的。
總結以下:
因此向量時鐘算法的實質是:
上面算法中的這種 A,B 之間不存在可以將某一個向量的尾端順着同一個節點連到另外一個向量中間的事件 和 用一個多維的時間來代替一維的時間 的時空觀,和狹義相對論中的時空觀很是相似。
在狹義相對論中,同一事件從不一樣的慣性參考系中觀察是不同的,而兩次事件能夠創建因果關係的前提是:兩個事件之間能夠用等於或小於光速的速度傳遞信息(或者說一事件位於另外一事件的光錐內部)。
聯繫:
在狹義相對論中的描述 | 在向量時鐘算法中的描述 |
不一樣的慣性參考系有不一樣的時間 | 不一樣的節點有不一樣的時鐘向量維度 |
兩件事件具備因果關係(事件 2 位於事件 1 的光錐內部) | 兩次更改可肯定前後順序(兩個向量具備偏序,相似光錐內部) |
兩件事件不具備因果關係(事件 2 位於事件 1 的光錐外部) | 兩件事件不具備因果關係(事件 2 位於事件 1 的光錐外部) |
更詳細的關於時鐘向量算法和狹義相對論時空觀的比較能夠閱讀參考文獻 3。
區別:
狹義相對論能夠用洛倫茲變換將不一樣的參考系中的時間進行變換(利用到不一樣參考系之間的相對速度),可是向量時鐘算法不能夠(其實邏輯上也能夠,可是實現後沒有現實意義),因此只能用多維的時間來表徵不一樣節點中的時間卻無法相互轉化。