手把手教你用PHP完成一個分散式事務TCC

藏色散人
發布: 2023-04-10 17:06:01
轉載
4150 人瀏覽過

什麼是TCC,TCC是Try、Confirm、Cancel三個詞語的縮寫,最早是由Pat Helland 於2007 年發表的一篇名為《Life beyond Distributed Transactions:an Apostate's Opinion》的論文提出。

TCC組成

TCC分為3個階段

  • Try 階段:嘗試執行,完成所有業務檢查(一致性),預留必須業務資源(準隔離)
  • Confirm 階段:如果所有分支的Try都成功了,則走到Confirm階段。 Confirm真正執行業務,不作任何業務檢查,只使用 Try 階段預留的業務資源
  • Cancel 階段:如果所有分支的Try有一個失敗了,則走到Cancel階段。 Cancel釋放 Try 階段預留的業務資源。

TCC分散式事務裡,有3個角色,與經典的XA分散式事務一樣:

  • AP/應用程序,發起全域事務,定義全域事務包含哪些事務分支
  • RM/資源管理器,負責分支事務各項資源的管理
  • TM/事務管理器,負責協調全域事務的正確執行,包括Confirm,Cancel的執行,並處理網路異常

如果我們要進行一個類似於銀行跨行轉帳的業務,轉出(TransOut)和轉入(TransIn)分別在不同的微服務裡,一個成功完成的TCC事務典型的時序圖如下:

手把手教你用手把手教你用PHP完成一個分散式事務TCC完成一個分散式事務TCC

TCC實務

#下面我們進行一個TCC事務的具體開發

目前可用於TCC的開源框架,主要為Java語言,其中以seata為代表。我們的範例採用nodejs,使用的分散式事務框架為dtm,它對分散式事務的支援非常優雅。下面來詳細講解TCC的組成

下面我們來編寫具體的Try/Confirm/Cancel的處理函數

$vega->handleFunc('/api/TransOutTry', function (Mix\Vega\Context $ctx) {
    var_dump('TransOutTry', $ctx->request->getQueryParams(), $ctx->request->getParsedBody());
    $ctx->JSON(200, ['result' => 'SUCCESS']);})->methods('POST');$vega->handleFunc('/api/TransOutConfirm', function (Mix\Vega\Context $ctx) {
    var_dump('TransOutConfirm', $ctx->request->getQueryParams(), $ctx->request->getParsedBody());
    $ctx->JSON(200, ['result' => 'SUCCESS']);})->methods('POST');$vega->handleFunc('/api/TransOutCancel', function (Mix\Vega\Context $ctx) {
    var_dump('TransOutCancel', $ctx->request->getQueryParams(), $ctx->request->getParsedBody());
    $ctx->JSON(200, ['result' => 'SUCCESS']);})->methods('POST');$vega->handleFunc('/api/TransInTry', function (Mix\Vega\Context $ctx) {
    var_dump('TransInTry', $ctx->request->getQueryParams(), $ctx->request->getParsedBody());
    $ctx->JSON(200, ['result' => 'SUCCESS']);})->methods('POST');$vega->handleFunc('/api/TransInConfirm', function (Mix\Vega\Context $ctx) {
    var_dump('TransInConfirm', $ctx->request->getQueryParams(), $ctx->request->getParsedBody());
    $ctx->JSON(200, ['result' => 'SUCCESS']);})->methods('POST');$vega->handleFunc('/api/TransInCancel', function (Mix\Vega\Context $ctx) {
    var_dump('TransInCancel', $ctx->request->getQueryParams(), $ctx->request->getParsedBody());
    $ctx->JSON(200, ['result' => 'SUCCESS']);})->methods('POST');
登入後複製

到此各個子事務的處理函數已經OK了,然後是開啟TCC事務,進行分支呼叫

    Dtmcli\tccGlobalTransaction($dtm, function ($tcc) use ($svc) {
        /** @var Dtmcli\Tcc $tcc */
        $req = ['amount' => 30];
        $tcc->callBranch($req, $svc . '/TransOutTry', $svc . '/TransOutConfirm', $svc . '/TransOutCancel');
        $tcc->callBranch($req, $svc . '/TransInTry', $svc . '/TransInConfirm', $svc . '/TransInCancel');
    });
登入後複製

至此,一個完整的TCC分散式事務編寫完成。

如果您想要完整運行一個成功的範例,那麼參考這個例子yedf/dtmcli-php-sample,將它運行起來非常簡單

# 部署启动dtm# 需要docker版本18以上git clone https://github.com/yedf/dtmcd dtm
docker-compose up# 另起一个命令行https://github.com/yedf/dtmcli-php-sample.gitcd dtmcli-php-sample
composer installphp demo.php start
登入後複製

TCC的回滾

假如銀行將金額準備轉入用戶2時,發現用戶2的帳戶異常,回傳失敗,會怎麼樣?我們可以讓TransIn回傳失敗來模擬這個情況

$vega->handleFunc('/api/TransInTry', function (Mix\Vega\Context $ctx) {
    var_dump('TransInTry', $ctx->request->getQueryParams(), $ctx->request->getParsedBody());
    $ctx->JSON(200, ['result' => 'FAILURE']);})->methods('POST');
登入後複製

我們給交易失敗互動的時序圖

手把手教你用手把手教你用PHP完成一個分散式事務TCC完成一個分散式事務TCC

這個跟成功的TCC差別就在於,當某個子事務回傳失敗後,後續就回滾全域事務,呼叫各個子事務的Cancel操作,確保全域事務全部回滾。

在TCC交易模式上,有不少的讀者會問,如果Confirm/Cancel失敗會怎麼樣?這是一個好問題,代表您正在深入思考TCC事務模式。第一種情況是臨時失敗,例如網路故障、應用程式或資料庫宕機,這類錯誤進行重試,最後會返回成功;另一種情況為業務失敗,按照TCC的協議,第一階段鎖定資源,保證足夠的資源能夠讓Confirm/Cancel執行,也就是說,程式邏輯上,Confirm/Cancel是不允許返回業務失敗的,如果出現業務失敗,那麼是bug,需要開發人員手動修復bug。

小結

在這篇文章裡,我們介紹了TCC的理論知識,也透過一個例子,完整給出了寫一個TCC事務的過程,涵蓋了正常成功完成,以及成功回滾的情況。相信讀者透過這邊文章,對TCC已經有了深入的理解。

關於分散式事務更多更全面的知識,請參考《分散式事務最經典的七種解決方案

文中使用的範例節選自yedf /dtm(https://github.com/yedf/dtm),它支援多種事務模式:TCC、SAGA、XA、事務訊息跨語言支持,已支援golang、python、Java、手把手教你用手把手教你用PHP完成一個分散式事務TCC完成一個分散式事務TCC、nodejs等語言的客戶端,參考各語言SDK(https://dtm.pub/summary/code.html#go)。提供子事務屏障功能,優雅解決冪等、懸掛、空補償等問題。

閱讀完此篇乾貨,歡迎大家造訪github.com/yedf/dtm項目,給顆星星支持!

以上是手把手教你用PHP完成一個分散式事務TCC的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
php
來源:learnku.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!