轉賬交易這件小事,是如何被程式設計師玩壞的?
很久很久以前。應用APP只有一個,功能都寫在一起。資料庫也只有一個,所有的資料一致性問題也可以通過事務解決。轉賬交易當然是小菜一碟:
try{ transaction.begin(); db.execute(A-1000); db.execute(B+1000); transaction.commit(); }catch(Exception e){ transaction.rollback(); }

轉賬-單機.png
後來隨著應用的複雜,需要拆分出多個領域單獨部署應用和資料庫。比如A賬戶屬於借記卡領域,而B賬戶屬於信用卡領域。我們可以用分散式事務,也可以用補償機制:

轉賬-多機多庫 .png
NOTE:基於兩階段提交的分散式事務並不能100%保證一致性(比如在第二階段資料庫發生當機)。基於補償的最終一致性方案,也有需要人工介入的情況。
上面的方案並不完善,沒有把考慮網路問題考慮進來。在跨公司遠端訪問中,網路問題會比較突出和頻繁。

轉賬-遠端互動.png
在複雜的網路情況下。除了成功和失敗,可能遇到沒有響應或超時的情況,這種情況下對方可能收到的請求也可能沒收到請求。可能處理了,也可能沒處理。如果重試一定次數後始終呼叫不成功,就需要人工介入。

轉賬-遠端同步.png
我們首先需要引入一張交易事務流水錶,來記錄賬戶每次的變更情況和狀態。賬戶資料只儲存最新的狀態。考慮到可能存在的重複提交,在被呼叫方也需要流水錶,來實現實現“冪等性”。
其次考慮到轉賬可能失敗,我們加入一個凍結資產的概念F,使得使用者可以明確看到這部分資金
當然交易可能是非同步的,接收方可能需要做一些別的處理才返回

轉賬-遠端非同步.png