說到分散式事務,大家並不陌生。在實際工作中,用得比較多的還是柔性分散式事務,今天主要把在工作中運用到的幾種柔性分散式事務的場景及實現方式做一個簡單介紹,也可以看做是柔性分散式事務的一個演進過程。 ...
說到分散式事務,大家並不陌生。在實際工作中,用得比較多的還是柔性分散式事務,今天主要把在工作中運用到的幾種柔性分散式事務的場景及實現方式做一個簡單介紹,也可以看做是柔性分散式事務的一個演進過程。
一、調用方保證
這種方式適合業務內自己使用,當方法內的任務一個邏輯發生異常時,整個方法都異常,由調用方進行重試。該方法不太適合於外部系統的交互,否則,這就是把自己的命運交到別人的手裡,是比較危險的做法。
在上述調用示意圖中,內部應用APP1和APP2之間,APP1的方法method1調用APP2里的method2方法,method2里有分散式事務邏輯,當分散式事務中的邏輯異常後,method2方法都失敗或拋出異常,method1收到返回值是失敗或異常後,都需要重試調用method2,確保method2執行成功。method2本身則需要確保邏輯中已經成功的邏輯再次被調用時處理也要正確。
@DistributedTransaction
method2(){
//write DB
//send msg
//RPC invoke
}
該方法不建議大家在工作中使用,僅從保證分散式事務的正確性看是可以使用的,但從Java的規範上看,這種方法屬於用異常控制流程,並不是很規範。同時,如果分散式事務中的邏輯是寫本地庫,發消息或RPC遠程調用,則一般不建議把事務和發消息或RPC調用放到事務方法內,避免大事務。
二、定時任務掃描業務表
該場景主要運用於流量小、業務場景較單一的場景,或是業務處於驗證階段,為了快速驗證業務是否有價值階段,直接用業務表來做任務表,避免建多張表。在用本地事務寫完業務表後,事務正常提交即可。通過一個定時任務查詢業務表的增量數據,在定時任務中處理其他業務邏輯。
@Transaction
void method1(){
//write DB1 Bueiness Table
//other business Logic
}
void method2(){
//查詢DB1中的Bueiness Table,時間從上次任務開始執行的時間開始
//處理自身的業務邏輯
}
該方案一般作為過渡方案,最終業務量上來後,會升級到下麵的本地任務表的方案。
三、本地任務表
這是比較典型的分散式事務的解決方案,即:在業務庫中,同步建一個任務表。業務表和任務表在本地事務中同時寫入,再由一個定時任務定時查詢任務表,把任務讀取到後根據業務邏輯要求進行處理。
業務表和任務表在一個資料庫中,由資料庫的一個事務控制器實現事務。在應用中,另起一個定時任務,由定時任務去查詢任務表,把任務表中新進的任務抓取後執行該定時任務需要執行的業務邏輯。
@Transaction
void method1(){
//write DB1 Bueiness Table
//write DB1 Task Table
}
void method2(){
//定時查詢DB1中的Task Table
//任務抓取後執行自身的業務邏輯
}
該方案實際運用時,定時任務的穩定性需要我們特別關註,定時任務的穩定性決定我們該方案的可用性。建議把定時任務的執行情況監控起來,確保有問題時能第一時間處理,避免影響業務。
四、組件抽取
目前,對於Java語言開發的團隊,其框架大部分都以Spring為主,故可基於SpringEvent非同步事件做一個小的組件封裝。主要思路為在事務中,發送Event非同步事件,當非同步事件發送成功則事務提交結束,當非同步事件發送失敗則非同步任務落本地資料庫後事務再提交結束,然後通過定時任務從任務表中抓取任務執行。
該方案以SpringEvent非同步事件為主做了一個組件,當SpringEvent非同步事件發送異常後,降級到本地任務表,確保非同步任務的可靠性。即使沒有封裝為組件,在實際工作中,還是比較推薦大家使用該方案。
@Transaction
void method1(){
//業務數據寫入DB成功
try{
//發送SpringEvent事件
}catch(Exception ex){
//寫入本地任務表
}
}
void method2(){
//接收事件或定時任務的數據執行業務邏輯
}
當然,如果項目中沒有使用Spring框架也沒問題,有了上述的思想,可以根據自身使用的框架情況進行調整。正所謂“只要思想不滑坡,辦法總比困難多”。
作者:京東物流 廖宗雄
來源:京東雲開發者社區 自猿其說Tech 轉載請註明出處