數據一致性這個單詞在日常開發中,或者各類文章中都能常常看見,咱們經常聽見什麼東西數據不一致了,形成了必定的損失,趕快修復一下。可是不少同窗對一致性具體表明什麼意思,他有什麼做用依然不是很瞭解,今天咱們就來聊聊一致性。面試
通常來講數據一致性咱們能夠分紅三類,時間點一致性,事務一致性,應用一致性。算法
時間點一致性我以爲也能夠叫作副本一致性,時間點一致性的定義爲:sql
若是全部相關的數據組件在任意時刻都是一致的,那麼能夠稱做爲時間點一致性。數據庫
這個定義若是你瞭解過CAP理論的話,那麼你應該不會太陌生。(若是不熟悉的同窗能夠看我這篇文章分佈式事務)編程
在CAP中的C的定義爲對某個指定的客戶端來講,讀操做能返回最新的寫操做。咱們能夠發現時間點並無規定一致的須要保證是最新的,因此可能有同窗會提出疑問時間點一致性的範圍比CAP中的一致性範圍要大一點。其實細想一下若是咱們某個數據組件更新了數據,若是爲了知足時間點一致性,那麼咱們全部相關的數據組件的數據都是一致的,因此其餘的數據都會變爲最新的,那麼其實就和CAP是同樣的,都須要知足若是在某個節點更新了數據,那麼在其餘節點若是都能讀取到這個最新的數據。緩存
固然CAP和時間點一致性並非徹底的一致:時間點一致性的定義中要求全部數據組件的數據在任意時刻都是徹底一致的,可是通常來講信息傳播的速度最大是光速,其實並不能達到任意時刻一致,總有必定的時間不一致,對於咱們CAP中的一致性來講只要達到讀取到最新數據便可,達到這種狀況並不須要嚴格的任意時間一致。網絡
這裏咱們還須要注意的是這個並不老是用於分佈式系統中的,在咱們單個機器中若是有多核處理器,咱們再任意時刻訪問不一樣處理器對同一變量數據都須要是一致的也能夠一樣適用。併發
一致性不只僅能夠表示數據的同時變動或相同性,還能夠用來表示約束,而咱們的事務一致性就是其中的一種。事務一致性就是咱們平時所說的ACID中的C,其定義以下:app
事務的一致性指的是在一個事務執行以前和執行以後數據庫都必須處於一致性狀態。若是事務成功地完成,那麼系統中全部變化將正確地應用,系統處於有效狀態。若是在事務中出現錯誤,那麼系統中的全部變化將自動地回滾,系統返回到原始狀態。分佈式
事務一致性只能存在在事務開始前的和事務完成以後,在事務過程當中數據有可能不一致。舉個例子:好比A轉100元給B,A扣減100,B加上100,在事務開始前和事務完成以後都能保證他們的賬是對上的,那麼這就是事務一致性。可是在事務過程當中有可能會出現A扣減了100元,B沒有加上100元的狀況,這就是不一致。
這裏通常的初學者都會把CAP和ACID中的C都會誤解成同樣的含義,其實他們其中一個表示的數據的相同,而另外一個是用來表示某種約束。
應用一致性能夠看作是約束一致性中的一種。上面的事務一致性表明的是單一數據源,若是數據源是多個,好比數據源有多個數據庫,文件系統,緩存等。那麼就須要咱們應用一致性,這裏也看作是分佈式事務一致性。
在應用程序中涉及多個不一樣的單機事務,只有在全部的單機事務完成以前和完成以後,數據是徹底一致的。好比給用戶發送券和積分,券服務和積分服務是兩個服務,他們各自有本身單機事務,這兩個單機單機事務開始前和完成後都能保證用戶的賬是對應上的。可是在這兩個單機事務執行過程有可能會出現只送了券,沒有送積分的狀況,有可能狀態不正確。
這三種一致性能夠簡單的看作兩類,一個是數據副本一致,另外一個是數據約束一致。接下來我更多的會介紹數據副本的一致的類型,而數據約束的一致,能夠參考我以前寫過的分佈式事務的那篇文章。
再寫這篇文章以前,我一直覺得一致性就那麼幾個常據說的,強一致,弱一致,最終一致。再查詢了一些文獻資料以後發現一致性的類型真的是很是的多,這裏我挑選一些比較重要的
若是有人問你你知道哪些一致性模型呢?不少人立刻答出,強一致,最終一致。其實一致性的模型遠遠不止這麼點,在《Operational Characterization of Weak Memory Consistency Models》這篇論文當中描述了15種弱內存一致模型,而在維基百科對內存模型的描述還有更多。
不少一致性的模型最開始是用來描述內存是否一致的,也就是最開始並非運用於分佈式系統當中的。若是咱們的機器是單核的話,那麼他的內存必定是強一致的。若是咱們的機器是多核的話,那麼因爲處理器並非直接訪問的內存而是訪問的處理器獨享的緩存,那麼就有可能會出現不一致。再分佈式中咱們的每一個節點其實就能夠當作一個獨立的處理器,而咱們最初運用於內存一致性模型,也能夠運用於咱們分佈式系統當中。下面我會從強到弱講講一些常見的一致性模型。
線性一致性又叫作原子一致性,強一致性。線性一致性能夠看作只有一個單核處理器,或者能夠看作只有一個數據副本,而且全部操做都是原子的。在可線性化的分佈式系統中,若是某個節點更新了數據,那麼在其餘節點若是都能讀取到這個最新的數據。能夠看見線性一致性和咱們的CAP中的C是一致的。
舉個非線性一致性的例子,好比有個秒殺活動,你和你的朋友同時去搶購同樣東西,有可能他那裏的庫存已經沒了,可是在你手機上顯示還有幾件,這個就違反了線性一致性,哪怕過了一會你的手機也顯示庫存沒有,也依然是違反了。
線性一致性有什麼做用呢?在《DDIA》這本書中描述了下面3個做用:
順序一致性弱於嚴格一致性。對變量的寫操做不必定要在瞬間看到,可是,不一樣處理器對變量的寫操做必須在全部處理器上以相同的順序看到,這裏處理器再分佈式系統中能夠換成不一樣的節點。
這裏咱們又再回到Zookeeper究竟是什麼一致性?有不少面試題都會問到Zookeeper是CP仍是AP呢?不少人都會回答到Zookeeper是CP,其實這個回答並非很嚴謹的,咱們從線性一致性中知道CAP中的一致性指的是線性一致性,那咱們就能夠說Zookeeper是線性一致性的嗎?答案是否認的。當咱們寫入一個值的時候,會交由Leader去處理,Zab協議只須要保證半數從節點成功便可,那麼就會有節點的數據是老的數據,這樣客戶端就有可能讀出的數據並不是是最新的從而破壞了線性一致性。
Zookeeper其實實現的是順序一致性,在ZK中利用zxid(ZooKeeper Transaction Id),實現了總體順序一致性,固然也能夠認爲Zookeeper的的寫是線性一致性,讀是順序一致性。從節點經過zxid順序的接收leader的廣播,因此ZK不能保證全部的信息立刻看到,可是最終都會看到。固然Zookeeper其實能夠實現線性化,在ZK中有一個sync()命令,只要咱們每次讀的時候都去調用sync()強制同步數據,那麼咱們都能保證其是最新的。
順序一致性是由Lamport(Paxos算法的做者)提出的,最開始只用來定義多處理內存的一致性,在Lamport的《How to Make a Multiprocessor Computer That Correctly Executes Multiprocess Programs》中其定義了什麼是順序一致性:
the result of any execution is the same as if the operations of all the processors were executed in some sequential order, and the operations of each individual processor appear in this sequence in the order specified by its program.
這句話的大體意思是多處理器的執行效果和單個處理器的執行效果是同樣的,每一個獨立的處理器的操做都會按照指定的順序出如今操做隊列。這個最開始是用於併發編程的,可是讓多處理器的執行變得和單處理器的確是沒啥做用,後來就用於分佈式系統當中。在ZK中全部的寫操做都會交給Leader節點去作,而且全部操做的更新都會根據zxid的順序進行更新,這裏就是上面所說的指定的順序,這個隊列就是按照zxid的順序。
因果一致性是弱於順序一致性的一致性模型,順序一致性要求全部的操做的順序都必須按照某個單個處理器(節點)的順序,而因果一致性只須要知足有因果關係的操做是順序一致性便可。
怎麼理解因果關係呢?簡單來講若是有人問你一個問題,那麼你給出答案,這兩個就是因果關係,但若是你給出答案再問題以前,那麼這個就違反了因果關係。 舉個簡單的例子若是節點1更新了數據A,節點2讀取數據A,並更新數據B,這裏的數據B有多是根據數據A計算出來的,全部具有因果關係,可是若是節點3看到的是先更新的B,再更新的A那麼就破壞了因果一致性。
處理器一致性是更加弱的一致性模型,他只須要保證處理器看到某個處理器或者多個不一樣處理對相同位置的寫入都是一致的。不須要考慮因果關係,而是對同一個內存或者同一個數據更新須要看到一致的順序。
FIFO一致性是比處理器一致性還更加弱的一種,它不須要保證對相同位置的寫入是一致的。 是指在一個處理器上完成的全部寫操做,將會被以它實際發生的順序通知給全部其它的處理器;可是在不一樣處理器上完成的寫操做也許會被其它處理器以不一樣於實際執行的順序所看到。這個在分佈式系統中反映了網絡中不一樣節點的延遲多是不相同的。爲了說明其和處理器一致性不一樣有以下例子:
上面這個圖中,能夠發現是違反了處理器一致性的,爲何呢由於寫入順序是w(x)1,w(x)2而,p4應該是先R(x)1再R(x)2。可是這個符合FIFO一致性,FIFO只須要把本身的發生順序通知給其餘的處理器或者節點,不須要保證同一個值寫入順序是一致的。
其實除了強一致之外,其餘的一致性均可以看做爲最終一致性,只是根據一致性不一樣模型的不一樣要求又衍生出了不少具體一致性模型。固然最簡單的最終一致性,是不須要關注中間變化的順序,只須要保證在某個時間點一致便可。只是這個某個時間點須要根據不一樣的系統,不一樣業務再去衡量。再最終一致性完成以前,有可能返回任何的值,不會對這些值作任何順序保證。
BASE理論中的E就是最終一致。
上面介紹了這麼多一致性模型,咱們瞭解到越強的一致性他的約束條件就越多,若是咱們實現的話成本那麼也就會越大。能夠看見ZK若是想實現徹底的線性一致性,那麼他就須要隨時都調用sync()去進行同步數據。
再咱們真實的場景中咱們數據庫的主從複製模型(經過binlog複製也是順序一致性),從庫的很大做用就是爲了緩解主庫的讀壓力,若是咱們想盲目的達到線性化一致性,那麼就必須去訪問主庫,這樣咱們的從庫的意義就微乎其微了。
因此根據不一樣的系統的模型,不一樣的業務要求,咱們對於一致性的要求是不一樣的,因此咱們瞭解這些一致性的模型是有不少必要的。
這篇文章主要是介紹了什麼是一致性,包括不少一致性模型,這裏少講了兩個一致性事務一致性和應用一致性,有興趣的能夠閱讀分佈式事務。還有一個值得一提的是,談到一致性其實就離不開共識,由於當數據副本有多個的時候,到底選擇誰,如何選擇纔是正確的,這個有興趣的同窗能夠自行查閱一些資料,好比Raft,Paxos和Zab等。
最後也再給你們幾個問題:
歡迎留言和我討論,固然最好是關注個人公衆號和我一塊兒探討哦,若是你們以爲這篇文章對你有幫助,你的關注和轉發是對我最大的支持,O(∩_∩)O:
參考文檔:
如何理解Zookeeper的順序一致性:https://blog.csdn.net/cadem/article/details/80359270
How to Make a Multiprocessor Computer That Correctly Executes Multiprocess Programs,Lamprot
Operational Characterization of Weak Memory Consistency Models:https://mp.weixin.qq.com/s/gg4q_53eiHCI3OUWzN7eWg
Designing Data-Intensive Applications, Martin Kleppman