今天,看了58沈劍的一篇文章《冗餘數據一致性,到底如何保證?》,覺得寫得非常的不錯,因此做了一些實驗,然後把內容分享出來。
在什麼情況下,需要數據冗餘
當我們在設計數據庫的時候,因為某些數據庫中的數據量非常大,所以我們常常會選擇進行數據庫的切割,而針對數據量的這種情況,水平切割是一種常用的方式。
當使用水平切割時,我們通常會選擇一個切割的維度,也就是選擇一個patition key。我現在在做一個B2B的平臺,每天會有大量的訂單,作為店鋪,會有一個ShopId,作為買家,會有一個UserId。
當我們查詢店鋪訂單時,如果ShopId是我們的patition key,那查詢就比較簡單,但,這是如果我們想要查詢買家的訂單時,就需要查詢多庫。反之,如果UserId是patition key,那麼買家查詢方便了,但是店鋪查詢就麻煩了。
針對這種情況,我們就可以把同一個數據冗餘兩份,一個使用UserId分庫,一個使用ShopId分庫。
如何有效的進行數據冗餘呢?
1)服務同步雙寫
如果我們需要數據冗餘,那麼可以在服務執行時,同時向兩個數據庫寫入數據。
這種解決方案的優點就是:
簡單,代碼中直接向兩個數據庫插入數據就行了;數據一致性相對較高,因為兩次插入完成後才回返回。當然,缺點也比較明顯:
假設,我們需要提高處理的時間,那麼我們可以使用下面這種解決方案,也是一種比較常用的解決方案。
2)服務異步雙寫
在這個方案裡,通過引入了消息總線,和數據同步中心,讓數據不再是通過服務來一次完成雙寫了。服務會異步向消息總線發出一個消息,然後通知數據同步中心來完成冗餘數據的寫入。
這個方案的優點我們已經說過了,就是:
處理時間快。由於只請求一次數據庫,其他都異步的完成。當然,缺點也應運而生:
系統複雜性增加了。因為多了一個消息總線和數據同步中心服務。(對於已經使用消息總線的小夥伴就相對簡單許多);數據極短時間內無法一致。由於第二次寫入是異步的,可能在請求返回時,異步數據寫入還沒有完成,因此,會有短暫的數據不一致。(絕大多數業務場景中,這一點點時間的不一致大多都可以忽略);消息總線可能丟失消息,那麼數據就會出現不一致。(這種情況極少出現)。當然,沈劍還介紹了第三種方案,這種我沒有試驗過,說是能夠實現冗餘數據的解耦。
3)線下異步雙寫
這種方式類似於數據庫的訂閱同步一樣,冗餘數據的寫入不再是通過服務來完成的了,而是通過一個線下的服務或者任務來完成的。
線下的服務或者任務通過讀取日誌記錄來完成冗餘數據的寫入。
這種方式的優點:
將冗餘數據的寫入和業務完全解耦,怎麼去寫冗餘數據和業務服務以及無關了;處理時間快。(原因同第二種方式)。缺點當然也是有的:
數據不一致性,和第二種方式一樣,這也是異步插入冗餘數據,那就會有短暫的時間出現數據不一直;線下服務必須可靠,不然數據一致性難保證。不管我們使用哪種方式,系統總有可能出現這樣那樣的異常,特別是在高併發的情況下。當這些異常出現時,我們就需要一個手段,來將不一致的數據最終實現一致。
因此,就必須完成:異步檢測、異步修復。
如何保證數據的最終一致性
沈劍在他的文章裡介紹了三種方法,這裡,我也就將這三種方法分享給大家。
1)線下全量數據掃描
線下啟動一個離線的掃描工具,不停的掃描對比T1表和T2表的數據,一旦發現數據不一致,就進行修復。
這樣做的優點:
簡單,開發的方便;無需修改線上服務,離線掃描工具與線上業務完全解耦。缺點也非常明顯:
掃描效率低,大部分時間,都在掃描已經一致的數據;掃描量大,因此同步數據的時間週期比較長。有沒有辦法不用每次都掃描全部數據,只是有針對性的進行掃描呢?
2)線下增量數據掃描
我們修改線上的服務,讓它在每次寫入數據的時候,同時寫入一個日誌。然後,我們同樣需要一個離線的掃描工具,只是這個掃描工具每次只是增量的掃描日誌,如果發現日誌數據不一致,就進行修復。
這樣做以後:
雖然增加了一些步驟,但依舊非常簡單,開發的難度不高;數據掃描效率提高了,只需要掃描增量數據。但:
我們需要對線上服務進行調整(只是多寫兩次日誌,非常簡單);雖然掃描效率提高了,但是實時性還是不高,主要是取決於掃描增量數據的週期時間。有沒有一個能夠實時監測的方式呢?
3)線上實時監測“消息對”法
這次,我們將服務進行改造,不在寫入日誌,改成向總線發送一個消息。在數據寫入成功後,就發送一個消息,兩次寫入,就發送了兩次消息。這時,我們不再需要一個掃描工具了,而是需要一個實時訂閱消息的服務,不停的去收這些消息,當收到第一次寫入成功的消息後一定時間內,沒有收到第二次消息,就去檢測數據的一致性,如果發現不一直,就進行修復。
這樣做以後:
實時性高;效率高。但也有缺點:
方案比較複雜,需要使用到消息總線;需要一個訂閱總線的檢測服務。具體我們需要使用哪種解決方案,就需要根據我們實際的業務需求來判斷了。技術本來就沒有一個絕對的方法,我們需要考慮投入和產出,因此,不一定缺點明顯的方案就不是好方案。