異地多活的數據一致性簡單設計


概述

異地多活,往往意味着誇機房讀寫延遲的增加,也就增加了讀寫失敗的可能性,最終導致數據的延遲更長,同時,這種場景下也會影響在線系統的性能和時延。本文從數據低延遲、開發復雜度上考慮,總結了兩種處理方式,分別是雙寫和雙讀,從而保證數據的最終一致性。對於異地多活的業務場景,往往也不需要保證強一致性,允許短時間的不一致性。例如對於外賣軟件,在南方點了外賣,然后到北方出差,常規上也不可能短時間內(分鍾級別)從南方飛到北方。
再舉個極端的例子,我們所看到星空中的行星的光,也很多是很多年前從很遠的宇宙發射過來的,你不可能在同一時間看到光。
再者,實現真正的異地多活(強一致,多節點寫入)是個極其復雜的工程,需要底層數據庫、業務上的支持,對於一致性要求沒那么高的業務場景,我們可以選擇稍微簡單的方案實現。

雙寫

寫入本機房后,還需要寫入異地機房,同步方式可以有:
  1. 數據庫本身支持了同步:這種情況往往需要增加第三方組件,例如阿里的 otter組件支持了mysql的同步。業務代碼只需要寫一次,底層數據同步交給數據庫,會出現短時間的兩個機房數據不一致的情況,業務上往往能夠接受。但極端情況也會出現異地對同一份數據進行寫,導致寫寫沖突,這時候需要業務介入做抉擇(常見的方式如訂單系統后期的對賬補償)。如果對於數據庫的操作是數據庫級別的原子性操作,例如redis的incr命令,就可以避免寫寫沖突。
  2. 數據庫本身不支持同步:這種情況需要業務代碼雙寫,跨區寫的失敗率會變高,采取重試,但會加劇數據的延遲(如果延遲不高,也能接收)。同時,如果是在線系統,往往並發量比較大,所以還是得在業務層面加MQ,如加入第三方的MQ(如kafka),實現上就得實現producer和consumer邏輯,而且還需要額外對kafka進行維護,這也帶來了系統的復雜性。簡單做法是采用內存隊列,直接寫入內存隊列,通過定時器定期消費內存隊列數據。如果數據支持批量接口,采用批量寫數據庫,讀的時候,只讀本機房數據。這種方式,也會有問題:因為是內存隊列,如果服務重啟,還沒來得及消費的數據會丟失;或者是多次寫失敗重試后依然失敗,也會導致數據丟失(其實這種情況需要發出告警,人工介入了)。如果業務允許有一定的數據丟失的情況,但對時效性要求較高的,采用這種方式比較合理。

雙讀

跟雙寫的讀本機房相反,改成只寫本機房,讀雙機房。這種方式,首先對於高並發的讀,非常不友好,跨區讀的時延太高,同步讀往往會導致超時或者影響在線時延。所以一般采用異步的方式,由一個異步線程把數據從另一個機房撈出來再寫入本地機房數據庫,讀的時候只讀本地機房數據庫庫。這種方式加大了延遲,好處是提高了並發度,盡量的減少對讀的影響,而且如果本地支持冪等性,還能保證數據的最終一致。數據從異地同步到本地的機制可以兩種:
  1. 全量同步:實現簡單,但只適合於數據量少,但如果數據太多,同步也會很慢,加大了延遲,有可能打滿網卡導致影響整體服務環境。
  2. 增量同步:實現復雜,需要設置個游標,類似kafka的offset,記錄本次同步到的點,如何標准游標是准確的呢?需要保證不多也不少,例如如果游標粒度設置的太大,同一個游標可能對應多個數據,這樣可能導致撈過來的數據比原有的多。所以這種情況對游標的選擇就比較重要了。

高並發下的優化方案

批量:無論是對於雙讀還是雙寫,都采用數據庫的批量接口,減少網絡io。

異步+雙隊列緩存

    • 異步:對於雙寫方案,采用異步寫;對於雙讀方案,采用異步讀更新(這種情況除非是增量更新,否則如果全量更新,也會導致性能和延遲的增加;但全量更新就要求數據不能太多,而且如果數據庫是redis或者其他kv,需要提前知道對應的key)。
    • 雙隊列緩存:雙buffer是為了提高並發度,對於雙寫,可以只需要對內存中的寫進行互斥,但對於數據的更新不會互斥,因為兩者個用不同隊列;對於雙讀,數據結構可以參考我之前發的doublybufferdata數據結構。對於隊列,其實是傳統MQ的替代,只是如果引入MQ,則需要帶來額外的維護成本,所以可以簡單的實現,用set或者map都可以。

總結

雙讀和雙寫的本質區別其實是數據在哪一邊同步的問題,類似kafka的producer和consumer,不可能放在同一個機房,要么producer端是誇機房,要么是consumer端是誇機房。無論是哪種方案,都會面臨延遲和不一致問題,以及還有性能問題,要兼顧延遲性、一致性、性能等,實現起來極其復雜,需要根據業務需要選擇一種折中的方案。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM