最近在做一個項目,其中一個方案涉及到跨庫事務一致性問題,是一個簡單的場景。這個項目是對老的業務進行性能提升,業務邏輯基本上保持不變。主要是在於新項目采用了分庫分表的設計,從而提升了性能。考慮到項目發布之后可能存在風險,采取了新老系統的並行方案。這個系統的業務比較簡單:接收來自外部的數據,然后對數據進行核對處理。為了保證新老系統能夠並行,在接收數據的時候必須實現雙寫方案,從而導致了跨庫事務的一致性問題。
下面一幅圖展示這一簡單的場景
這里面會存在一個小問題,就是可能存在寫入老庫成功,但是寫入新庫失敗的場景。
我們假設出現這種概率的情況是百萬分之一,在系統發布的情況下,這種概率可能更高。從目前我們的數據量來看,一天大概5000W,那么出現不一致的數據量在500條。考慮到這個是數據核算系統,不能有一條丟失的情況,否則兩邊比對結果可能會不一致。所以需要保證一致性。
這種問題,有以下幾種解決方案
1 考慮使用JTA等支持分布式事務的事務管理器
這種方案的優勢就是直接有現成的解決方案,一般的j2ee服務器都提供了JTA的相關的實現。比較明顯的問題就是解決方案太重量級。一般JTA除了服務器要支持,對應的數據庫服務廠商一般也要提供相應的商業支持,主要是提供基於 XAResource JDBC驅動,這一些商業上的支持,部分是需要付費的。而且使用XA 數據庫驅動,本身可能導致一些潛在的問題,尤其是基於不同的數據庫廠商的時候。而XA是基於兩階段提交協議,事務管理器為了完成一個事務,需要多次和數據庫通信,效率上比較低。
2 考慮使用數據庫自身的數據同步機制
如果新老庫的結構基本一樣,這種方案還是比較靠譜的。也是比較簡單的方案。這種方案的局限性也再次。在本項目中,新庫不是一個物理庫,而是多個物理庫,而老庫是一個物理庫。如果要用數據庫自身的同步機制,涉及到多個庫和一個庫之間的數據復制。同時由於分表的方案也不一樣,導致兩邊做一個映射的配置,而這個需要在數據庫層面進行,邏輯相當的復雜,解決方案成本也比較高。相當於把重要的分庫分表的邏輯在數據庫這一層重新實現了一份。
其實這個也帶來一個維護問題,一旦我們覺得新系統已經足夠穩定。應用程序可以之間在寫入庫進行切換,把老庫的邏輯切掉,從而實現了只寫新庫的需求。整個過程也不需要進行再次發布。而數據庫的方案則需要停掉腳本,在多個地方進行配置。
3 在old庫存放相同的兩張模型表,一張表用於old庫的持久化表,另外一張作為臨時表,主要是作為需要同步到到新庫的數據。如果已經同步到新庫,就刪除。如果沒有同步到新庫就同步到新庫。這個過程采用定時機制,每分鍾定時提取臨時表一定數據量的數據,批量導入到新庫。通過努力重試,來保證一致性。而新庫則需要保證冪等性,保證數據只會同步過一次。一般情況下,則是通過數據特征標識符來識別,這個一般都是數據的唯一性主鍵。
下面是簡單的實現:
這三種方案的主要思想就是 采取重試機制,這個只是分布式事務里面的一種模型,相應的還有兩階段提交,異常恢復補償等機制。