通俗的給你講什么是線性一致性讀!
你知道的越多,不知道的就越多,業(yè)余的像一棵小草!
你來,我們一起精進(jìn)!你不來,我和你的競爭對手一起精進(jìn)!
編輯:業(yè)余草
推薦:https://www.xttblog.com/?p=5165
通俗的給你講什么是線性一致性讀!
一致性是分布式系統(tǒng)的一大難題,幾乎所有架構(gòu)師和資深程序員都會面臨如何平衡它。剛好最近又有粉絲在群里問我一致性問題,當(dāng)時(shí)我簡單闡述了一些,本文稍微整理了一下,分享出來,大家共勉!
什么時(shí)一致性
一致性是指數(shù)據(jù)處于一種語義上的有意義且正確的狀態(tài)。一致性是對數(shù)據(jù)可見性的約束。
說白了就是讓數(shù)據(jù)保持一致,在分布式系統(tǒng)中,可以理解為多個(gè)節(jié)點(diǎn)中數(shù)據(jù)的值是一致的。
一致性分類
一致性的分類有很多種。比如:強(qiáng)一致性和弱一致性。
強(qiáng)一致性
強(qiáng)一致性可以理解為在任意時(shí)刻,所有節(jié)點(diǎn)中的數(shù)據(jù)是一樣的。同一時(shí)間點(diǎn),你在節(jié)點(diǎn) A 中獲取到 key1 的值與在節(jié)點(diǎn) B 中獲取到 key1 的值應(yīng)該都是一樣的。
弱一致性
弱一致性包含很多種不同的實(shí)現(xiàn),分布式系統(tǒng)中廣泛實(shí)現(xiàn)的是最終一致性。
最終一致性
所謂最終一致性,是弱一致性的一種特例,保證用戶最終能夠讀取到某操作對系統(tǒng)特定數(shù)據(jù)的更新。但是隨著時(shí)間的遷移,不同節(jié)點(diǎn)上的同一份數(shù)據(jù)總是在向趨同的方向變化。也可以簡單的理解為在一段時(shí)間后,節(jié)點(diǎn)間的數(shù)據(jù)會最終達(dá)到一致狀態(tài)。
對于最終一致性最好的例子就是 DNS 系統(tǒng),由于 DNS 多級緩存的實(shí)現(xiàn),所以修改 DNS 記錄后不會在全球所有 DNS 服務(wù)節(jié)點(diǎn)生效,需要等待 DNS 服務(wù)器緩存過期后向源服務(wù)器更新新的記錄才能實(shí)現(xiàn)。
除了強(qiáng)弱一致性,一致性還可以分為:數(shù)據(jù)一致性和事務(wù)一致性。
另外還有,讀寫一致性、單調(diào)讀、因果一致性等。這些我后面抽出時(shí)間都會來一一寫,今天我還是主要說線性一致性讀。
線性一致性讀
線性一致讀是在分布式系統(tǒng)中實(shí)現(xiàn) Java volatile 語義,當(dāng)客戶端向集群發(fā)起寫操作的請求并且獲得成功響應(yīng)之后,該寫操作的結(jié)果要對所有后來的讀請求可見。實(shí)現(xiàn)線性一致讀常規(guī)手段是走 Raft 協(xié)議,將讀請求同樣按照 Log 處理,通過日志復(fù)制和狀態(tài)機(jī)執(zhí)行獲取讀結(jié)果返回給客戶端。
舉個(gè)簡單的例子。在 t1 的時(shí)刻我們寫入了一個(gè)值,那么在 t1 之后,我們一定能讀到這個(gè)值,不可能讀到 t1 之前的舊值(Java 中的 volatile 關(guān)鍵字,即線性一致讀就是在分布式系統(tǒng)中實(shí)現(xiàn) Java volatile 語義)。
簡而言之是需要在分布式環(huán)境中實(shí)現(xiàn) Java volatile 語義效果,即當(dāng) Client 向集群發(fā)起寫操作的請求并且獲得成功響應(yīng)之后,該寫操作的結(jié)果要對所有后來的讀請求可見。和 volatile 的區(qū)別在于 volatile 是實(shí)現(xiàn)線程之間的可見,而線性一致讀針對的是分布式系統(tǒng)之間的可見性。

如上圖 Client A、B、C、D 均符合線性一致讀,其中 D 看起來是 Stale Read,其實(shí)并不是,D 請求橫跨 3 個(gè)階段,而 Read 可能發(fā)生在任意時(shí)刻,所以讀到 1 或 2 都行。
實(shí)現(xiàn)線性一致讀最常規(guī)的辦法是走 Raft 協(xié)議,針對該協(xié)議可以查看我之前的文章,比如:。
基本的想法是讓一個(gè)系統(tǒng)看起來好像只有一個(gè)數(shù)據(jù)副本,而且所有的操作都是原子性的(線性一致寄存器的行為就好像只有單個(gè)數(shù)據(jù)副本一樣,且每個(gè)操作似乎都是在某個(gè)時(shí)間點(diǎn)以原子性的方式生效的)。
一旦新的值被寫入或讀取,所有后續(xù)的讀都會看到寫入的值,直到它被再次覆蓋。尤其要注意,如果 B 的讀取嚴(yán)格發(fā)生于 A 的讀取之后(他們讀取的值正在被 C 寫入),那么只要 A已經(jīng)讀取到 C 寫入的新值,B 就必須返回 C 寫入的新值,即使 C 的寫入仍在進(jìn)行中。
線性一致的系統(tǒng)驚人的少。例如,現(xiàn)代多核 CPU 上的內(nèi)存甚至都不是線性一致的: 如果一個(gè) CPU 核上運(yùn)行的線程寫入某個(gè)內(nèi)存地址,而另一個(gè) CPU 核上運(yùn)行的線程不久之后讀取相同的地址,并沒有保證一定能讀到第一個(gè)線程寫入的值(除非使用了內(nèi)存屏障(memorybarrier)或圍欄(fence)。
在線性一致的數(shù)據(jù)在存儲中是不存在并發(fā)操作的:必須有且僅有一條時(shí)間線,所有的操作都在這條時(shí)間線上,構(gòu)成一個(gè)全序關(guān)系??赡苡袔讉€(gè)請求在等待處理,但是數(shù)據(jù)存儲確保了每個(gè)請求都是在唯一時(shí)間線上的某個(gè)時(shí)間點(diǎn)自動處理的,不存在任何并發(fā)。對比之下,因果關(guān)系只是偏序關(guān)系。如果兩個(gè)操作都沒有在彼此之前發(fā)生,那么這兩個(gè)操作是并發(fā)的,如果兩個(gè)事件是因果相關(guān)的(一個(gè)發(fā)生在另一個(gè)事件之前),則它們之間是有序的,但如果它們是并發(fā)的,則它們之間的順序是無法比較的。這意味著因果關(guān)系定義了一個(gè)偏序,而不是一個(gè)全序。
以上,希望能夠?qū)Υ蠹矣兴鶐椭?/p>
最后,推薦幾篇相關(guān)文章!
為什么每個(gè)面試官都和數(shù)據(jù)一致性過不去?
一致性協(xié)議算法-2PC、3PC、Paxos、Raft、ZAB、NWR超詳細(xì)解析
