<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          用Java輕松完成一個分布式事務TCC,自動處理空補償、懸掛、冪等

          共 3435字,需瀏覽 7分鐘

           ·

          2021-12-01 21:02

          作者:葉東富

          來源:SegmentFault  思否社區(qū)


          處理NPC



          分布式系統最大的敵人可能就是NPC了,在這里它是Network Delay, Process Pause, Clock Drift的首字母縮寫。我們先看看具體的NPC問題是什么:


          • Network Delay,網絡延遲。雖然網絡在多數情況下工作的還可以,雖然TCP保證傳輸順序和不會丟失,但它無法消除網絡延遲問題。

          • Process Pause,進程暫停。有很多種原因可以導致進程暫停:比如編程語言中的GC(垃圾回收機制)會暫停所有正在運行的線程;再比如,我們有時會暫停云服務器,從而可以在不重啟的情況下將云服務器從一臺主機遷移到另一臺主機。我們無法確定性預測進程暫停的時長,你以為持續(xù)幾百毫秒已經很長了,但實際上持續(xù)數分鐘之久進程暫停并不罕見。

          • Clock Drift,時鐘漂移?,F實生活中我們通常認為時間是平穩(wěn)流逝,單調遞增的,但在計算機中不是。計算機使用時鐘硬件計時,通常是石英鐘,計時精度有限,同時受機器溫度影響。為了在一定程度上同步網絡上多個機器之間的時間,通常使用NTP協議將本地設備的時間與專門的時間服務器對齊,這樣做的一個直接結果是設備的本地時間可能會突然向前或向后跳躍。


          分布式事務既然是分布式的系統,自然也有NPC。分布式事務可分為

          • 分布式數據庫內部的分布式事務:NPC中的C給這類應用,帶來了極大的挑戰(zhàn),例如Spanner采用了原子鐘,并且增加了Commit-Wait來解決問題。TiDB采用單點授時,引入了一個單點。

          • 跨數據庫的異構分布式事務:這是我們這篇文章討論的主題,因為沒有涉及時間戳,所以NPC帶來的困擾主要是NP。


          TCC的空補償與懸掛



          我們以分布式事務中的TCC(Try,Confirm,Cancel)作為例子,關于TCC模式的詳細介紹可以參考:分布式事務最經典的七種解決方案
          文章鏈接:
          https://segmentfault.com/a/1190000040321750

          一般情況下,一個TCC回滾時的執(zhí)行順序是,先執(zhí)行完Try,再執(zhí)行Cancel,但是由于N,則有可能Try的網絡延遲大,導致先執(zhí)行Cancel,再執(zhí)行Try。

          這種情況就引入了分布式事務中的兩個難題:

          1. 空補償:Cancel執(zhí)行時,Try未執(zhí)行,事務分支的Cancel操作需要判斷出Try未執(zhí)行,這時需要忽略Cancel中的業(yè)務數據更新,直接返回

          2. 懸掛:Try執(zhí)行時,Cancel已執(zhí)行完成,事務分支的Try操作需要判斷出Cancel一致性,這時需要忽略Try中的業(yè)務數據更新,直接返回


          分布式事務還有一類需要處理的常見問題,就是重復請求,業(yè)務需要做冪等處理。因為空補償、懸掛、重復請求都跟NP有關,我們把他們統稱為子事務亂序問題。在業(yè)務處理中,需要小心處理好這三種問題,否則會出現錯誤數據。

          現有方案的問題



          我看到開源項目dtm之外,包括各云廠商,各開源項目,他們給出的業(yè)務實現建議大多類似如下:

          開源項目dtm地址:

          https://github.com/yedf/dtm


          • 空補償:“針對該問題,在服務設計時,需要允許空補償,即在沒有找到要補償的業(yè)務主鍵時,返回補償成功,并將原業(yè)務主鍵記錄下來,標記該業(yè)務流水已補償成功。”

          • 防懸掛:“需要檢查當前業(yè)務主鍵是否已經在空補償記錄下來的業(yè)務主鍵中存在,如果存在則要拒絕執(zhí)行該筆服務,以免造成數據不一致。”


          上述的這種實現,能夠在大部分情況下正常運行,但是上述做法中的“先查后改”在并發(fā)情況下是容易掉坑里的,我們分析一下如下場景:

          • 正常執(zhí)行順序下,Try執(zhí)行時,在查完沒有空補償記錄的業(yè)務主鍵之后,事務提交之前,如果發(fā)生了進程暫停P,或者事務內部進行網絡請求出現了擁塞,導致本地事務等待較久

          • 全局事務超時后,Cancel執(zhí)行,因為沒有查到要補償的業(yè)務主鍵,因此判斷是空補償,直接返回

          • Try的進程暫停結束,最后提交本地事務

          • 全局事務回滾完成后,Try分支的業(yè)務操作沒有被回滾,產生了懸掛


          事實上,NPC里的P和C,以及P和C的組合,有很多種的場景,都可以導致上述競態(tài)情況,就不一一贅述了。

          雖然這種情況發(fā)生的概率不高,但是在金融領域,一旦涉及金錢賬目,那么帶來的影響可能是巨大的。

          PS:冪等控制如果也采用“先查再改”,也是一樣很容易出現類似的問題。解決這一類問題的關鍵點是要利用唯一索引,“以改代查”來避免競態(tài)條件。

          子事務屏障技術



          下面我們來詳解dtm是如何解決這個問題的。

          dtm首創(chuàng)了子事務屏障技術,用于同時解決空補償、防懸掛、冪等這三個問題,對于TCC事務,他的詳細工作過程如下:

          1. 在本地數據庫中創(chuàng)建好子事務屏障表dtm_barrier.barrier,唯一索引為gid-branchid-branchop

          2. 對于Try、Confirm、Cancel操作,insert ignore一條記錄gid-branchid-try|confirm|cancel,如果影響行數為0(重復請求、懸掛),直接提交返回

          3. 對于Cancel操作額外再insert ingore一條記錄 gid-branchid-try,如果影響行數為1(空補償),直接提交返回

          4. 執(zhí)行業(yè)務邏輯并提交返回,如果業(yè)務發(fā)生錯誤則回滾


          假如Try和Cancel的執(zhí)行時間沒有重疊,那么讀者容易分析出上述過程能夠解決空補償和懸掛問題。如果出現了Try和Cancel執(zhí)行時間重疊的情況,我們看看會發(fā)生什么。

          假設Try和Cancel并發(fā)執(zhí)行,Cancel和Try都會插入同一條記錄gid-branchid-try,由于唯一索引沖突,那么兩個操作中只有一個能夠成功,而另一個則會等持有鎖的事務完成后返回。

          • 情況1,Try插入gid-branchid-try失敗,Cancel操作插入gid-branchid-try成功,此時就是典型的空補償和懸掛場景,按照子事務屏障算法,Try和Cancel都會直接返回

          • 情況2,Try插入gid-branchid-try成功,Cancel操作插入gid-branchid-try失敗,按照上述子事務屏障算法,會正常執(zhí)行業(yè)務,而且業(yè)務執(zhí)行的順序是Try在Cancel前

          • 情況3,Try和Cancel的操作在重疊期間又遇見宕機等情況,那么至少Cancel會被dtm重試,那么最終會走到情況1或2。


          綜上各種情況的詳細論述,子事務屏障能夠在各種NP情況下,保證最終結果的正確性。

          事實上,子事務屏障有大量優(yōu)點,包括:

          • 兩個insert判斷解決空補償、防懸掛、冪等這三個問題,比其他方案的三種情況分別判斷,邏輯復雜度大幅降低

          • dtm的子事務屏障是SDK層解決這三個問題,業(yè)務完全不需要關心

          • 性能高,對于正常完成的事務(一般失敗的事務不超過1%),子事務屏障的額外開銷是每個分支操作一個SQL,比其他方案代價更小。


          上述的理論與分析過程也同樣適用于SAGA。dtm里面的子事務屏障同時支持了TCC和SAGA兩種事務模式。

          Java接入



          dtm是首個支持自動處理子事務亂序問題的開源框架,極大的減輕了業(yè)務負擔,降低了分布式事務的使用門檻。

          dtm已經提供了Java的SDK,包含了子事務屏障功能,幫助用戶自動處理子事務亂序問題。DTM提供的是一套SDK形式(非注解形式)的接口,易于理解和使用。

          我們編寫了一個非常完整的示例,該示例的主要功能模擬了一個跨行轉賬(跨服務轉賬)的業(yè)務場景,包含的內容有:如何組織子事務、如何做凍結資金、如何處理失敗、如何使用子事務屏障。您在這個例子的基礎上改一改,就能夠完成您實際的TCC分布式事務。

          這篇文章用Java輕松完成一個分布式事務TCC,自動處理空補償、懸掛、冪等給出了詳細的Java TCC事務原理與接入過程,方便用戶快速上手。
          文章鏈接:
          https://segmentfault.com/a/1190000041030430



          點擊左下角閱讀原文,到 SegmentFault 思否社區(qū) 和文章作者展開更多互動和交流,掃描下方”二維碼“或在“公眾號后臺回復“ 入群 ”即可加入我們的技術交流群,收獲更多的技術文章~

          - END -


          瀏覽 22
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美日韩一级二级 | 国产高清无码在线观看视频 | 精品无码视频在线 | 亚洲综合免费观看高清完整 | 亚洲视频日韩精彩动漫一区二区 |