數據一致性檢測的應用場景與實踐
隨著業務規模的擴張,企業系統變得越來越復雜,在這種復雜的分布式系統架構下,難免會出現遠程調用失敗,消息發送失敗,并發 bug 等等問題,這些問題最終會導致系統間的數據不一致,導致用戶體驗受損,用戶利益受損,對平臺來說就是產生資損。因此如何持續保障系統的業務穩定性對于企業來說是一個很重要的課題,本文旨在介紹一些常見業務應用場景下的業務數據一致性保障最佳實踐。
離線or在線,事前or事后
應對業務數據不一致問題的常規操作是,配置定時任務,在每個固定時間點去拉取歷史一段時間的數據出來進行比對,判斷是否有數據故障出現,比如利用hadoop做一些批處理MapReduce作業,這種離線計算的方式時效性比較差,對于電商系統或者對于實時性要求較高的系統來說,問題發現的越晚損失也就越大,所以我們需要一種在線的校驗模式來實時發現數據不一致問題。
在線的校驗模式指的是每出現一筆數據就進行一次比對,這種比對方式還可以分為事前和事后比對。
- 事前比對是一種業務強耦合的校驗方式,我們在業務系統代碼中進行類似 AOP 的操作,橫插一段校驗代碼,如果校驗發現問題,則阻斷這次業務操作,這種模式雖然時效性很高,能夠保證每一筆數據的正確性,但是因為和業務耦合的太重,很容易出現一些災難性的問題,比如校驗代碼的性能差或者異常處理不正確,會直接導致業務操作受阻,影響正常業務活動。
- 事后校驗嚴格上來說不能算是實時校驗,因為校驗的時間點滯后于真實的業務動作發生時間點,這算是一種準實時校驗,這種校驗的好處在于,可以和業務解耦,不阻斷業務的正常進行,還能較為"實時"的發現數據不一致問題,并且在一些特殊場景下(比如異步業務,下面會介紹)只能使用事后校驗,缺點也很明顯,就是時效性相比于事前校驗來說會比較差。
這里在啰嗦一句,可能讀到這里,有些人會問,既然是業務動作發生之后再進行校驗,它的意義還有多大呢?的確相比于事前校驗來說,他并不能保證每一筆數據都正確,但是在實際操作中,像電商這種場景下,我們進行業務功能迭代,會經過日常環境 -> 預發環境 -> Beta測試 -> 線上環境的流程,尤其是在預發環境和 Beta 測試的情況下,一般會進行一些線上引流或者模擬數據測試,特點是量小,即使發生問題也只是局部不會引起災難,那在這種場景下,事后校驗的意義就顯得很大,可以提前驗證功能和數據的正確性,又不會對線上造成強耦合的影響;在功能完全上線后,事后校驗的作用在于及時發現數據不一致問題,避免問題的進一步擴散。
綜上所述,對于業務數據校驗時效性不是那么高的場景下,離線校驗是一種比較合適的方式,開發接入成本都較低,對于業務數據校驗時效性有一些要求的場景下,事后校驗是一種比較適合的方式,對于業務校驗時效性要求非常嚴格,并且能夠投入較多資源的情況下,事前校驗比較適合。
數據一致性檢測實踐案例
案例一、會員系統
某店鋪會員入會業務,需要結合店鋪系統、打標系統、會員系統進行入會退會操作,如下圖所示:
在這個業務場景中,買家在店鋪會員頁發起入會申請,入會成功對外發送會員入會metaq消息,下游業務系統根據這個metaq消息,為該用戶打上一個標簽,用戶在下單的時候就根據這個標簽判斷是否有優先購買的權利。既然有入會就有退會,退會同樣發起metaq消息給用戶進行去標操作。所以不管入會還是退會,業務上要求店鋪系統的會員狀態(入會還是退會)必須和用戶系統的標簽狀態一致(有或者沒有),一旦發現數據不一致,一個已經退會的用戶如果還有用戶會員標簽,該用戶就可以購買這個限購商品,這樣就會造成商家資損。因此必須有對賬業務對數據一致性進行強保證,一旦發現數據不一致,必須要通知相關人員進行數據核對,如有問題則進行數據訂正。
這個案例在對賬系統的選擇上有如下幾個要求:
- 實時:必須當天盡快處理。
- 可以報警
- 必須支持不同領域模型。
- 接口調用需要有一定的延遲,以便下游系統處理完所有流程之后再校驗。
- 由于入會、退會metaq可能會有丟失或者亂序的情況,因此不可以根據該消息進行對賬。
在這個業務場景下,我們可以看到,業務是異步的,會員系統發起入會操作后,并不是立刻就能在用戶系統打標的,所以實時的事前校驗并不適合這個場景,因為在會員系統發起入會操作的時候在用戶系統中還查不到這個打標狀態,需要延遲一段時間去查,所以只能用事后校驗來做。
我們在這個場景的做法是:拉取店鋪會員數據庫的實時binlog日志數據,給到校驗系統,校驗系統解析日志數據拿到要打標的會員id,并且延時一段時間后去會員系統查詢這個會員的入會狀態,和日志中的狀態進行一致性比對,發現不一致則進行告警。
案例二、新老庫遷移
當新老系統需要進行更替的時候,經常會涉及到數據遷移,由于數據量非常大,而且不允許停機,所以遷移一定是一個循序漸進的過程,整個過程會分成兩個部分,第一個部分是雙寫,保證新增數據兩邊同步。第二步是開始做存量數據遷移,通過后臺任務慢慢跑。在這個過程中可能會出現部分字段沒有同步,更新數據順序錯亂導致數據內容不一致的問題,所以需要對遷移進行數據的一致性檢查,及時發現數據問題進行訂正或者bug修復。
由于我們的目的是將數據遷移到新系統,所以數據校驗觸發條件就是新系統有數據寫入,這里可能有人會問如果老系統同步失敗呢,那么新系統就不會有數據寫入,就觸發不了校驗。這里就存在校驗邊界的問題,即我們假設同步系統是一定會同步成功的,如果同步失敗的話不允許跳過會一直嘗試重試同步,所以這里如果發生同步失敗,同步會暫停并且打印出同步錯誤日志,這個就不是校驗系統的問題了,我們會通過同步的進度或者同步日志來觀察到這個現象。
所以我們在這個場景的做法是:接收新庫的數據庫變更binlog日志數據,解析日志內容,通過這條數據id去查詢舊庫的對應數據,進行數據內容的比對。由于雙寫的存在,一條數據可能會變更多次,這里就要求我們的校驗必須是較為實時的進行,否則就會出現拿到的日志數據內容是舊的(這條數據又發生了更新),導致查詢老庫的數據出現不一致的問題,其實算是一種誤報。