前言
在分布式系統中,雖然我們會使用各種分布式事務的方案,來保證各個系統之間的一致性。但是,很多時候往往事與愿違。
尤其是現在很多公司都采用最終一致性的方案,而所謂最終一致性,無論是本地消息表、事務消息、還是任務重試,系統之間的調用都是有可能失敗的。
而一旦發生失敗,就需要有一套機制來發現這些不一致的問題,這時候就需要做數據對賬了。
對賬時機
一般來說,根據對賬的時機分為兩種,離線對賬和(準)實時對賬。
實時對賬,一般來說基本都是準實時,也就是說并不能保證無延遲,但是一般可以控制在秒級別的延遲上。而離線對賬一般都是D+1的核對。
D+1:D指的是自然日,包括工作日和節假日。+1指的是第二天,也就是說數據發生后的第二天進行核對。
T+1:T指的是交易日,一般來說就是工作日,所以T+1指的就是數據發生后的下一個工作日進行核對。
技術實現
那么對賬的技術實現上一般主要就是兩種,要么是寫代碼核對,要么是寫SQL核對.
寫代碼就是查出需要比對的兩條記錄,然后進行字段的比對,不一致的就拋出來。
寫SQL就是做join查詢或者子查詢,然后通過where條件比較需要核對的字段,不一致的就拋出來。
寫代碼這種核對方式,一般來說都是通過定時任務實現的,通過運行定時任務,然后去掃表,或者去遠程拉數據然后在業務代碼中進行核對,這種方式的優點就是比較通用,不管是數據庫,還是文件,還是遠程接口,都可以做核對。缺點就是一旦數據量大了,代碼核對的時效性就會比較差,而且代碼運行存在失敗的可能。萬一數據量特別大,就可能會出現掃表掃不動,文件加載到內存導致OOM等問題。
所以,寫代碼的核對方式不推薦
那么,更好一點的方式就是寫SQL了,因為數據都在數據庫(數倉或者大數據框架)中,這些都可以通過SQL進行查詢,如下就是比較兩個系統中金額是否一致的SQL:
SELECT OUTbiz NO,bill NO,
OWNER
FROMbill item
WHEREOUT biz NO IN (AND charge ON amount - charge off amount = 0’ SELECTbiz id FROMcollectionCASEitem detail WHERECASEitem state = "COLLECTING" AND cur ovd principal >
那在哪寫這些SQL進行核對,就有很多種方案了,一般來說有以下幾個:
1、離線數倉,主要用于離線數據核對。我們現在每天會把需要離線存儲的數據同步到數倉中,然后在數倉中寫SQL進行數據的核對。
2、在線數據庫,離線核對的話發現問題比較慢,好一點的方案是在在線庫做核對,可以直接在數據庫中寫SQL進行數據核對。為了避免數據核對影響真實業務,可以考慮在備庫中執行SQL。但是有的時候數據核對可能是多個系統之間的,這時候就要做跨庫join,但是并不是所有的數據庫、所有的引都文持跨庫join的。
3、準實時數據庫,還有一種方案,那就是不直接在數據庫中寫SQL,而是把數據同步到其他的地方,比如通過監聽binlog的方式,把MYSQL的數據同步到實時數倉,比如我們公司內部用的就是AnalyticDB,把需要做核對的數據同步到ADB中,我們會盡量放到一個空間下面,然后在這里面寫SQL作核對。同步出來的這個ADB數據,不僅可以做核對,還可以用于查詢或者做報表,
4、ETL核對,還有一種比較常見的方案,那就是通過ETL工具進行數據核對,ETL包括了數據的提取、清洗、轉化及加工,所以在這個過程中也是可以做核對的。
5、flink核對,flink是一個非常牛X的流處理框架,可以通過fink進行數據核對。
核對與告警
有朋友提問:如果通過sql語句發現有不一致的數據,一般是怎么處理?是發告警通知開發人員還是說需要將有問題的數據標記出來過段時間重新核對?
我們一般來說,告警的話,人工一定要跟進
至于說過段時間重新核對,這種我們一般在報警規則中把他屏蔽掉了。有需要重新核對的,我們會做一些延遲核對,或者二次核對。或者直接報警規則設置成多次失敗后再報警,或者告警值調高一點
這樣就是職責單一,核對就是核對,報警就是報警。有報警人就要看,否則都是無效報警,那有效報警也沒人看了.
?