當我們使用冗餘數據存儲時 如何保證數據的一致性?

今天,看了58沈劍的一篇文章《冗餘數據一致性,到底如何保證?》,覺得寫得非常的不錯,因此做了一些實驗,然後把內容分享出來。

在什麼情況下,需要數據冗餘

當我們在設計數據庫的時候,因為某些數據庫中的數據量非常大,所以我們常常會選擇進行數據庫的切割,而針對數據量的這種情況,水平切割是一種常用的方式。

當我們使用冗餘數據存儲時 如何保證數據的一致性?

當使用水平切割時,我們通常會選擇一個切割的維度,也就是選擇一個patition key。我現在在做一個B2B的平臺,每天會有大量的訂單,作為店鋪,會有一個ShopId,作為買家,會有一個UserId。

當我們查詢店鋪訂單時,如果ShopId是我們的patition key,那查詢就比較簡單,但,這是如果我們想要查詢買家的訂單時,就需要查詢多庫。反之,如果UserId是patition key,那麼買家查詢方便了,但是店鋪查詢就麻煩了。

當我們使用冗餘數據存儲時 如何保證數據的一致性?

針對這種情況,我們就可以把同一個數據冗餘兩份,一個使用UserId分庫,一個使用ShopId分庫。

如何有效的進行數據冗餘呢?

1)服務同步雙寫

如果我們需要數據冗餘,那麼可以在服務執行時,同時向兩個數據庫寫入數據。

當我們使用冗餘數據存儲時 如何保證數據的一致性?

這種解決方案的優點就是:

  1. 簡單,代碼中直接向兩個數據庫插入數據就行了;
  2. 數據一致性相對較高,因為兩次插入完成後才回返回。

當然,缺點也比較明顯:

  1. 需要同時進行兩次寫操作,時間花費多。(實際測試中,其實人多一次寫還是兩次寫的時間上並不敏感);
  2. 可能存在數據不一致,例如第一次寫成功後,服務斷開。

假設,我們需要提高處理的時間,那麼我們可以使用下面這種解決方案,也是一種比較常用的解決方案。

2)服務異步雙寫

在這個方案裡,通過引入了消息總線,和數據同步中心,讓數據不再是通過服務來一次完成雙寫了。服務會異步向消息總線發出一個消息,然後通知數據同步中心來完成冗餘數據的寫入。

當我們使用冗餘數據存儲時 如何保證數據的一致性?

這個方案的優點我們已經說過了,就是:

  1. 處理時間快。由於只請求一次數據庫,其他都異步的完成。

當然,缺點也應運而生:

  1. 系統複雜性增加了。因為多了一個消息總線和數據同步中心服務。(對於已經使用消息總線的小夥伴就相對簡單許多);
  2. 數據極短時間內無法一致。由於第二次寫入是異步的,可能在請求返回時,異步數據寫入還沒有完成,因此,會有短暫的數據不一致。(絕大多數業務場景中,這一點點時間的不一致大多都可以忽略);
  3. 消息總線可能丟失消息,那麼數據就會出現不一致。(這種情況極少出現)。

當然,沈劍還介紹了第三種方案,這種我沒有試驗過,說是能夠實現冗餘數據的解耦。

3)線下異步雙寫

這種方式類似於數據庫的訂閱同步一樣,冗餘數據的寫入不再是通過服務來完成的了,而是通過一個線下的服務或者任務來完成的。

當我們使用冗餘數據存儲時 如何保證數據的一致性?

線下的服務或者任務通過讀取日誌記錄來完成冗餘數據的寫入。

這種方式的優點:

  1. 將冗餘數據的寫入和業務完全解耦,怎麼去寫冗餘數據和業務服務以及無關了;
  2. 處理時間快。(原因同第二種方式)。

缺點當然也是有的:

  1. 數據不一致性,和第二種方式一樣,這也是異步插入冗餘數據,那就會有短暫的時間出現數據不一直;
  2. 線下服務必須可靠,不然數據一致性難保證。

不管我們使用哪種方式,系統總有可能出現這樣那樣的異常,特別是在高併發的情況下。當這些異常出現時,我們就需要一個手段,來將不一致的數據最終實現一致。

因此,就必須完成:異步檢測、異步修復。

如何保證數據的最終一致性

沈劍在他的文章裡介紹了三種方法,這裡,我也就將這三種方法分享給大家。

1)線下全量數據掃描

線下啟動一個離線的掃描工具,不停的掃描對比T1表和T2表的數據,一旦發現數據不一致,就進行修復。

當我們使用冗餘數據存儲時 如何保證數據的一致性?

這樣做的優點:

  1. 簡單,開發的方便;
  2. 無需修改線上服務,離線掃描工具與線上業務完全解耦。

缺點也非常明顯:

  1. 掃描效率低,大部分時間,都在掃描已經一致的數據;
  2. 掃描量大,因此同步數據的時間週期比較長。

有沒有辦法不用每次都掃描全部數據,只是有針對性的進行掃描呢?

2)線下增量數據掃描

我們修改線上的服務,讓它在每次寫入數據的時候,同時寫入一個日誌。然後,我們同樣需要一個離線的掃描工具,只是這個掃描工具每次只是增量的掃描日誌,如果發現日誌數據不一致,就進行修復。

當我們使用冗餘數據存儲時 如何保證數據的一致性?

這樣做以後:

  1. 雖然增加了一些步驟,但依舊非常簡單,開發的難度不高;
  2. 數據掃描效率提高了,只需要掃描增量數據。

但:

  1. 我們需要對線上服務進行調整(只是多寫兩次日誌,非常簡單);
  2. 雖然掃描效率提高了,但是實時性還是不高,主要是取決於掃描增量數據的週期時間。

有沒有一個能夠實時監測的方式呢?

3)線上實時監測“消息對”法

這次,我們將服務進行改造,不在寫入日誌,改成向總線發送一個消息。在數據寫入成功後,就發送一個消息,兩次寫入,就發送了兩次消息。這時,我們不再需要一個掃描工具了,而是需要一個實時訂閱消息的服務,不停的去收這些消息,當收到第一次寫入成功的消息後一定時間內,沒有收到第二次消息,就去檢測數據的一致性,如果發現不一直,就進行修復。

當我們使用冗餘數據存儲時 如何保證數據的一致性?

這樣做以後:

  1. 實時性高;
  2. 效率高。

但也有缺點:

  1. 方案比較複雜,需要使用到消息總線;
  2. 需要一個訂閱總線的檢測服務。

具體我們需要使用哪種解決方案,就需要根據我們實際的業務需求來判斷了。技術本來就沒有一個絕對的方法,我們需要考慮投入和產出,因此,不一定缺點明顯的方案就不是好方案。


分享到:


相關文章: