|
DTM released version 0.1 from 2021-06-04, developing rapidly |
|
Judging from the characteristics compared above, DTM has great advantages in many aspects. If you consider multi-language support and multi-storage engine support, then DTM is undoubtedly your first choice.
Installation
It is very convenient to install dtm-client through Composer
composer require dtm/dtm-client
Copy after login
- Don’t forget to start the DTM Server when using it
Configuration
Configuration file
If you are using the Hyperf framework, after installing the component, you can use the following vendor:publish
command to publish the configuration file in ./config/autoload/dtm. php
php bin/hyperf.php vendor:publish dtm/dtm-client
Copy after login
If you are using it in a non-Hyperf framework, you can copy the ./vendor/dtm/dtm-client/publish/dtm.php
file to the corresponding configuration directory middle.
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' => [],
],
];
Copy after login
Configuring middleware
Before use, you need to configure DtmClient\Middleware\DtmMiddleware
The middleware is used as the global middleware of the Server, and the middleware supports the PSR-15 specification. , applicable to every framework that supports this specification.
For middleware configuration in Hyperf, please refer to the Hyperf Documentation - Middleware chapter.
Usage
The use of dtm-client is very simple. We provide a sample project dtm-php/dtm-sample to help everyone better understand and debug.
Before using this component, it is also strongly recommended that you read the official DTM documentation for a more detailed understanding.
TCC mode
TCC mode is a very popular flexible transaction solution, consisting of the acronyms of Try-Confirm-Cancel respectively. The concept was first proposed by Pat Helland in a paper titled "Life beyond Distributed Transactions: an Apostate's Opinion" published in 2007.
Three phases of TCC
Try phase: try to execute, complete all business checks (consistency), reserve necessary business resources (quasi-isolation)
Confirm stage: If the Try of all branches is successful, go to the Confirm stage. Confirm actually executes the business without any business checks, and only uses the business resources reserved in the Try phase.
Cancel phase: If one of the Trys of all branches fails, it goes to the Cancel phase. Cancel releases the business resources reserved during the Try phase.
If we want to conduct a business similar to an inter-bank transfer, the transfer (TransOut) and the transfer (TransIn) are in different microservices. The typical sequence diagram of a successfully completed TCC transaction is as follows:
Code example
The following shows how to use it in the Hyperf framework, other frameworks are similar
<?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();
}
}
Copy after login
Saga Pattern
The Saga pattern is one of the most famous solutions in the field of distributed transactions and is also very popular in major systems. It first appeared in the paper SAGAS published by Hector Garcaa-Molrna & Kenneth Salem in 1987. .
Saga is an eventually consistent transaction and a flexible transaction, also called a long-running transaction (Long-running-transaction). Saga is composed of a series of local transactions. After each local transaction updates the database, it will publish a message or an event to trigger the execution of the next local transaction in the Saga global transaction. If a local transaction fails because some business rules cannot be satisfied, Saga will perform compensating operations for all transactions that were successfully committed before the failed transaction. Therefore, when comparing Saga mode to TCC mode, it often becomes more troublesome to implement rollback logic due to the lack of resource reservation steps.
Saga sub-transaction split
For example, we want to perform a business similar to a bank inter-bank transfer, transfer 30 yuan from account A to account B, according to Saga The principle of the transaction, we split the entire global transaction into the following services:
- Transfer service, where the operation will be performed to deduct 30 yuan from account A
- Transfer Out Compensate (TransOutCompensate) service, roll back the above transfer out operation, that is, A's account will increase by 30 yuan
- Transfer in (TransIn) service, here B's account will increase by 30 yuan
- transfer Execute the compensation (TransInCompensate) service and roll back the above transfer operation, that is, the B account is reduced by 30 yuan
The logic of the entire transaction is:
Execute transfer successfully => Execute Transfer successful => Global transaction completed
If an error occurs in the middle, for example, an error occurs when transferring to account B, the compensation operation of the executed branch will be called, that is:
Execute transfer out Success => Failed to execute transfer-in=> Successfully executed transfer-in compensation=> Successfully executed transfer-out compensation=> Global transaction rollback completed
The following is a typical timing diagram of a successfully completed SAGA transaction :
代码示例
以下展示在 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();
}
}
Copy after login