关于php:🎉-DTM-分布式事务管理器-PHP-协程客户端-v01-beta-版本发布

https://github.com/dtm-php/dt…

介绍

dtm/dtm-client 是分布式事务管理器 DTM 的 PHP 客户端,已反对 TCC模式、Saga、二阶段音讯模式的分布式事务模式,并别离实现了与 DTM Server 以 HTTP 协定或 gRPC 协定通信,该客户端可平安运行于 PHP-FPM 和 Swoole 协程环境中,更是对 Hyperf 做了更加易用的性能反对。

对于 DTM

DTM 是一款基于 Go 语言实现的开源分布式事务管理器,提供跨语言,跨存储引擎组合事务的弱小性能。DTM 优雅的解决了幂等、空弥补、悬挂等分布式事务难题,也提供了简略易用、高性能、易程度扩大的分布式事务解决方案。

亮点

  • 极易上手

    • 零配置启动服务,提供非常简单的 HTTP 接口,极大升高上手分布式事务的难度
  • 跨语言

    • 可适宜多语言栈的公司应用。不便 Go、Python、PHP、NodeJs、Ruby、C# 等各类语言应用。
  • 应用简略

    • 开发者不再放心悬挂、空弥补、幂等各类问题,独创子事务屏障技术代为解决
  • 易部署、易扩大

    • 仅依赖 MySQL/Redis,部署简略,易集群化,易程度扩大
  • 多种分布式事务协定反对

    • TCC、SAGA、XA、二阶段音讯,一站式解决多种分布式事务问题

比照

在非 Java 语言下,暂未看到除 DTM 之外的成熟的分布式事务管理器,因而这里将 DTM 和 Java 中最成熟的开源我的项目 Seata 做比照:

个性 DTM SEATA 备注
反对语言 <span style=”color:green”>Go、C#、Java、Python、PHP…</span> <span style=”color:orange”>Java</span> DTM 可轻松接入一门新语言
存储引擎 <span style=”color:green”>反对数据库、Redis、Mongo等</span> <span style=”color:orange”>数据库</span>
异样解决 <span style=”color:green”> 子事务屏障主动解决 </span> <span style=”color:orange”>手动解决</span> DTM 解决了幂等、悬挂、空弥补
SAGA事务 <span style=”color:green”>极繁难用</span> <span style=”color:orange”>简单状态机</span>
二阶段音讯 <span style=”color:green”>✓</span> <span style=”color:red”>✗</span> 最简音讯最终一致性架构
TCC事务 <span style=”color:green”>✓</span> <span style=”color:green”>✓</span>
XA事务 <span style=”color:green”>✓</span> <span style=”color:green”>✓</span>
AT事务 <span style=”color:orange”>倡议应用XA</span> <span style=”color:green”>✓</span> AT 与 XA相似,但有脏回滚
单服务多数据源 <span style=”color:green”>✓</span> <span style=”color:red”>✗</span>
通信协议 HTTP、gRPC Dubbo等协定 DTM对云原生更加敌对
star数量 <img src=”https://cdn.learnku.com/uploads/images/202202/15/21058/zh9c3GAmYq.svg” alt=”github stars”/> <img src=”https://cdn.learnku.com/uploads/images/202202/15/21058/pn5f7zYuSG.svg” alt=”github stars”/> DTM 从 2021-06-04 公布 0.1版本,倒退飞快

从下面比照的个性来看,DTM 在许多方面都具备很大的劣势。如果思考多语言反对、多存储引擎反对,那么 DTM 毫无疑问是您的首选.

装置

通过 Composer 能够十分不便的装置 dtm-client

composer require dtm/dtm-client
  • 应用时别忘了启动 DTM Server 哦

配置

配置文件

如果您是在 Hyperf 框架中应用,在装置组件后,可通过上面的 vendor:publish 命令一件公布配置文件于 ./config/autoload/dtm.php

php bin/hyperf.php vendor:publish dtm/dtm-client

如果您是在非 Hyperf 框架中应用,可复制 ./vendor/dtm/dtm-client/publish/dtm.php 文件到对应的配置目录中。

use DtmClient\Constants\Protocol;
use DtmClient\Constants\DbType;

return [
    // 客户端与 DTM Server 通信的协定,反对 Protocol::HTTP 和 Protocol::GRPC 两种
    'protocol' => Protocol::HTTP,
    // DTM Server 的地址
    'server' => '127.0.0.1',
    // DTM Server 的端口
    'port' => [
        'http' => 36789,
        'grpc' => 36790,
    ],
    // 子事务屏障配置
    'barrier' => [
        // DB 模式下的子事务屏障配置
        'db' => [
            'type' => DbType::MySQL
        ],
        // Redis 模式下的子事务屏障配置
        'redis' => [
            // 子事务屏障记录的超时工夫
            'expire_seconds' => 7 * 86400,
        ],
        // 非 Hyperf 框架下利用子事务屏障的类
        'apply' => [],
    ],
    // HTTP 协定下 Guzzle 客户端的通用配置
    'guzzle' => [
        'options' => [],
    ],
];

配置中间件

在应用之前,须要配置 DtmClient\Middleware\DtmMiddleware 中间件作为 Server 的全局中间件,该中间件反对 PSR-15 标准,可实用于各个反对该标准的的框架。
在 Hyperf 中的中间件配置可参考 Hyperf文档 – 中间件 一章。

应用

dtm-client 的应用非常简单,咱们提供了一个示例我的项目 dtm-php/dtm-sample 来帮忙大家更好的了解和调试。
在应用该组件之前,也强烈建议您先浏览 DTM 官网文档,以做更具体的理解。

TCC 模式

TCC 模式是一种十分风行的柔性事务解决方案,由 Try-Confirm-Cancel 三个单词的首字母缩写别离组成 TCC 的概念,最早是由 Pat Helland 于 2007 年发表的一篇名为《Life beyond Distributed Transactions:an Apostate’s Opinion》的论文中提出。

TCC 的 3 个阶段

Try 阶段:尝试执行,实现所有业务查看(一致性), 预留必须业务资源(准隔离性)
Confirm 阶段:如果所有分支的 Try 都胜利了,则走到 Confirm 阶段。Confirm 真正执行业务,不作任何业务查看,只应用 Try 阶段预留的业务资源
Cancel 阶段:如果所有分支的 Try 有一个失败了,则走到 Cancel 阶段。Cancel 开释 Try 阶段预留的业务资源。

如果咱们要进行一个相似于银行跨行转账的业务,转出(TransOut)和转入(TransIn)别离在不同的微服务里,一个胜利实现的 TCC 事务典型的时序图如下:

<img src=”https://dtm.pub/assets/tcc_normal.dea14fb3.jpg” height=600 />

代码示例

以下展现在 Hyperf 框架中的应用办法,其它框架相似

<?php
namespace App\Controller;

use DtmClient\TCC;
use DtmClient\TransContext;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Throwable;

#[Controller(prefix: '/tcc')]
class TccController
{

    protected string $serviceUri = 'http://127.0.0.1:9501';

    #[Inject]
    protected TCC $tcc;

    #[GetMapping(path: 'successCase')]
    public function successCase()
    {
        try {
            
            $this->tcc->globalTransaction(function (TCC $tcc) {
                // 创立子事务 A 的调用数据
                $tcc->callBranch(
                    // 调用 Try 办法的参数
                    ['amount' => 30],
                    // Try 办法的 URL
                    $this->serviceUri . '/tcc/transA/try',
                    // Confirm 办法的 URL
                    $this->serviceUri . '/tcc/transA/confirm',
                    // Cancel 办法的 URL
                    $this->serviceUri . '/tcc/transA/cancel'
                );
                // 创立子事务 B 的调用数据,以此类推
                $tcc->callBranch(
                    ['amount' => 30],
                    $this->serviceUri . '/tcc/transB/try',
                    $this->serviceUri . '/tcc/transB/confirm',
                    $this->serviceUri . '/tcc/transB/cancel'
                );
            });
        } catch (Throwable $e) {
            var_dump($e->getMessage(), $e->getTraceAsString());
        }
        // 通过 TransContext::getGid() 取得 全局事务ID 并返回
        return TransContext::getGid();
    }
}

Saga 模式

Saga 模式是分布式事务畛域最有名气的解决方案之一,也十分风行于各大零碎中,最后呈现在 1987 年 由 Hector Garcaa-Molrna & Kenneth Salem 发表的论文 SAGAS 里。

Saga 是一种最终一致性事务,也是一种柔性事务,又被叫做 长时间运行的事务(Long-running-transaction),Saga 是由一系列的本地事务形成。每一个本地事务在更新完数据库之后,会公布一条音讯或者一个事件来触发 Saga 全局事务中的下一个本地事务的执行。如果一个本地事务因为某些业务规定无奈满足而失败,Saga 会执行在这个失败的事务之前胜利提交的所有事务的弥补操作。所以 Saga 模式在比照 TCC 模式时,因短少了资源预留的步骤,往往在实现回滚逻辑时会变得更麻烦。

Saga 子事务拆分

比方咱们要进行一个相似于银行跨行转账的业务,将 A 账户中的 30 元转到 B 账户,依据 Saga 事务的原理,咱们将整个全局事务,拆分为以下服务:

  • 转出(TransOut)服务,这里将会进行操作 A 账户扣减 30 元
  • 转出弥补(TransOutCompensate)服务,回滚下面的转出操作,即 A 账户减少 30 元
  • 转入(TransIn)服务,这里将会进行 B 账户减少 30 元
  • 转出弥补(TransInCompensate)服务,回滚下面的转入操作,即 B 账户缩小 30 元

整个事务的逻辑是:

执行转出胜利 => 执行转入胜利 => 全局事务实现

如果在两头产生谬误,例如转入 B 账户产生谬误,则会调用已执行分支的弥补操作,即:

执行转出胜利 => 执行转入失败 => 执行转入弥补胜利 => 执行转出弥补胜利 => 全局事务回滚实现

上面是一个胜利实现的 SAGA 事务典型的时序图:

<img src=”https://dtm.pub/assets/saga_normal.a2849672.jpg” height=428 />

代码示例

以下展现在 Hyperf 框架中的应用办法,其它框架相似

namespace App\Controller;

use DtmClient\Saga;
use DtmClient\TransContext;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;

#[Controller(prefix: '/saga')]
class SagaController
{

    protected string $serviceUri = 'http://127.0.0.1:9501';
    
    #[Inject]
    protected Saga $saga;

    #[GetMapping(path: 'successCase')]
    public function successCase(): string
    {
        $payload = ['amount' => 50];
        // 初始化 Saga 事务
        $this->saga->init();
        // 减少转出子事务
        $this->saga->add(
            $this->serviceUri . '/saga/transOut', 
            $this->serviceUri . '/saga/transOutCompensate', 
            $payload
        );
        // 减少转入子事务
        $this->saga->add(
            $this->serviceUri . '/saga/transIn', 
            $this->serviceUri . '/saga/transInCompensate', 
            $payload
        );
        // 提交 Saga 事务
        $this->saga->submit();
        // 通过 TransContext::getGid() 取得 全局事务ID 并返回
        return TransContext::getGid();
    }
}

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理