iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 3
1
Software Development

分散式系統 - 在分散的世界中保持一致系列 第 3

Day 3 - 從Replica Server讀到的資料一定正確嗎? Data Replication and Consistency

前言

昨天舉了一個很基本的例子,講了分散式系統怎麼開始的(傳送門)。
最重要的原因,就是因為我們希望將儲存的資料做replication儲存到多個servers上,來增加系統的Availability。

一切應該這麼簡單美好,沒想到居然跳出了Consistency的問題!
資料是會隨時間變動的,那沒辦法我們就必須去更新replica servers上的備份資料。
但是更殘酷的在後頭,海底電纜會被鯊魚咬斷、網路會斷線會掉封包或是其餘原因導致primary server和其餘replica servers可能斷線暫時無法通訊。
如果這時使用者/系統其他元件讀取了replica servers,豈不是讀到過時的資料?

你說那我規定所有的讀寫都讀primary server就好。
沒問題!那如果primary server掛掉了怎麼辦?
那我就用replica server做備份...(鬼打牆中XD)

上述應該讓大家直觀的感受到了,分散式系統的出現是必然,但是隨之而來的問題也是躲不開的。

而前一天提到了CAP理論,將整個問題歸納成基本上就是Consistency和Availability的取捨。
你要更強的Consistency,就必須讓承擔系統有時不可用的成本,與達成Consistency的設計成本。
你要更好的Availability,就必須接受有時讀到的資料不一定是最新的。

既然是工程師,我們有沒有辦法把這兩件事情再更細粒的劃分等級呢?方便我們設計分散式系統時做取捨?

你說的資料要一致有多一致?一直是很多學者在研究的方向,前面提出的Eventual Consistency就是其中一種設計方向。而目前也已經提出很多Consistency Model隨你選擇,我們來看看有哪些吧。

先來一場棒球賽吧!

Doug Terry (現職Amazon),在 2013 CACM article, Replicated Data Consistency Explained Through Baseball 提出用棒球賽與參與人員來解釋各種Consistency Model,以下將使用他的例子。

系統假設

首先我們需要有一個計分系統,儲存主隊客隊的分數

  1. 假設我們有一個key-value store系統,提供get(k)set(k,v)的操作,並且寫入一定寫進primary server,讀取則可以從replica server讀取,分散式儲存嘛~
  2. 對primary server的操作一定會同步到replica server上。
  3. 既然是計分系統,儲存的資料也就是key有兩個: 主隊/客隊
    而計分員寫入操作要1).先讀目前分數 2).再加上得分存回去
    主隊得分set(主, 1),主隊又得分,v=get(主);set(主,v+1)
  4. 操作本身也是有意義的,因此我們同步資料並不只是同步結果,
    而是連同操作本身也同步到replica server去,比方說primary server同步set(主, 4)這個操作到replica server去。

現在我們有了儲存分數的分散式系統,但是replica server的資料同步強度要求還沒決定,
所以我們來分類幾種文章提到的不同的Consistency Model所造成的行為。

Consistency Model

我們要先知道的是Consistency Model本質上是 對系統的要求,對Client的保證

假設比賽今天來到七局上半,客隊進攻

  1. Strong Consistency: 對於任一個觀看球賽的人,系統保證他讀到的主/客隊比分都一定是最新的。可能讀到的值: 客隊:2,主隊:5 因此比分2-5

  2. Eventual Consistency(易搞混): 在t時刻讀取主/客隊,可能讀到t時刻之前的任一值。只能保證最後每一個replica會完成更新所有操作,此時會讀到最正確的值,但是Client沒辦法知道什麼時候
    因此比分什麼都有可能,在第七局上半
    讀取客隊分數可能為:0,1,2,讀取主隊分數可能為:0,1,2,3,4,5
    因此某一個replica server 可能讀到客隊:2,主隊1,因此比分2-1,該結果除了不是第七局上半的比分,甚至是根本沒發生過的!

  3. Consistent Prefix: 還記得前面提到會連同操作一起存起來嗎? 這種Consistency要求的讀取一定是一連串順序寫入的某一時刻的值。也就是說他讀到的一定是比賽中某一刻正確的比分,雖然不一定是最新的。
    可能讀到的比分: 2-3,也就是第五局結束的比分
    此性質在資料庫領域稱為 snapshot isolation,也就是某一時刻讀到的結果一定是primary server之前某一刻的snapshot,因此結果一定也是符合約束。

  4. Bounded Staleness: 可以參數化這個 bounded值,保證取到的值一定是這個t以內的結果。
    比方說規定 bounded 為一回合內(第六局後的值)
    讀取客隊分數可能為:2,讀取主隊分數可能為:3,4,5
    可以發現如果
    bounded=無限 => 退化成Eventual Consistency
    bounded=0 => 進化成Strong Consistency

  5. Monotonic Reads: Client一開始讀取x的值,可能返回任何結果(跟Eventual Consistency一樣),但是接下來Client會持續從同一個replica server讀取,並保證讀取到的值會比第一次讀的值越來越新
    第一次讀取客隊分數=1,接下來=1,2,第一次讀取主隊分數=3,接下來為:3,4,5

  6. Read My Writes: 如果一個client對系統set(主,5),他接下來的get(主)一定得到5

選擇

有這麼多選擇,問題回到設計者身上,你的使用情境所要求的Consistency強度到底有多強。

因此回到賽場上,假設你是以下幾個身份,你應該用哪一種等級的Consistency Model呢?

  1. 計分員: 你的任務就是每次讀取目前分數並記錄上新的分數。因為全場只有你一個計分員會寫入系統,因此只要要求他讀的一定是他剛剛寫入的,使用 Read My Writes 即可完成要求

  2. 裁判: 裁判很重要,他只做一次讀取,就是在第九局結束比賽時讀取主隊/客隊比分,判定勝負。他不允許讀到不是最新的資訊,因此必須使用Strong Consistency

  3. 廣播報分員: 每三十分鐘播報一次比數,不一定要報最新一局的比數,現在第七局我可以說目前三局上比分1-1,對聽眾不是很重要。但是也不能因此播報錯誤的比分誤導聽眾,所以使用Consistent Prefix。但是!Consistent Prefix每次讀可能是不同局數,總不能這次報第五局比分,30分鐘過後變成報第三局比分。因此我們同時必須搭配Monotonic Reads來保證每一次報比分都會越來越新。

這邊可以看到其實不同的Consistency Model是可以合併使用,Consistency是一個要求,你可以對自己的系統同時施加很多要求。

  1. 報社記者: 等待比賽結束後,去悠閒的吃個晚餐,等到晚上坐在書桌前再讀取比分寫成明日報導。因此他只需要使用Bounded Staleness,在半夜書桌前開始要寫報導時,使用1-hour Bounded Staleness 一定可以讀到最新的資料,總不會系統在我吃完晚餐半夜了還沒辦法同步所有資料到replica server吧?

  2. 觀眾: 隨時看個比數,跟朋友聊聊棒球。這個用Eventual Consistency即可(笑)。畢竟比分對他來說不是那麼重要,只要最後能讀到最新分數就好,中間每次看到的分數不是最新或是錯誤的都不會出重大問題。

討論

  • 也許你會說,上面的所有情境我都可以使用Strong Consistency。讓每個人都能看到最新的比分不是很好嗎?但是,Strong Consistency實現非常困難與複雜,會增加系統的成本同時使得Availability降低(CAP的例子記得嗎?)

  • 計分員為什麼用 Read My Writes 而不是 Strong Consistency,不同Model到底差別在哪?
    A:
    當我們從理論過渡到實作的時候,要求的強度等級,這件事就變得很重要了!
    想像primary server在美國,計分員在台灣。
    他也許寫入的時候需要將分數寫到在美國的primary server。但是他讀取的時候在保證 Read My Writes 性質下,他不用等到所有的replicas都更新成最新的資料(strong consistency),而只需要讀取系統保證已經更新了最新一次寫入的replica servers就可以了,而該replica server可能就在台灣,因此讀取時間更快。

  • 最後,上面這些是要求,他可以有多種實作的方法,比方使用2PC/Raft/Paxos一致性演算法來做到Strong Consistency。Eventual Consistency就是最隨緣的一種,primary server每收到一個操作我就傳遞給replica server,什麼時候傳到我不知道,我必須另外想辦法保證反正最後一定傳得到。

總結

除了上面的Consistency Models以外,當然還有很多不同的Model存在,設計系統時可以找尋最適合自己使用情境的Model。

我們以為做data replication一定要做到隨時隨地任一個replica server都是最新的,其實不用。而是根據情境與成本去做選擇。

回到現實中的例子:

  • 如果是金融系統,不用想一定是Strong Consistency,一個Eventual Consistency的系統誰敢用XD
  • DNS,你的域名註冊後過十秒另一端還無法解析是可以忍受的吧(?),那我們就用Eventual Consistency啦,還可以增加全球DNS系統的可用性和可擴展性(Scalibility)。

現在雲端蓬勃發展,Google/Microsoft/Amazon都發展自己的公有雲。透過在世界各地建造機房來增加分散式系統的可用性,Consistency這個議題當然對他們非常重要,重要到在各種使用文件都會有說明他們是哪種Consistency Model,提供你在選擇服務時的一個重要參考!

現在的你,應該可以知道他們到底在說什麼了吧?

[延伸閱讀]


上一篇
Day 2 - 我的C是你的C嗎,介紹CAP Theorem與ACID/BASE
下一篇
Day 4 - DynamoDB設計裡Consistency與Availability的爭奪 - Quorum System(上)
系列文
分散式系統 - 在分散的世界中保持一致30

尚未有邦友留言

立即登入留言