|
| DTM publié 0 à partir du 04/06/2021 version .1, en développement rapide |
À en juger par les caractéristiques comparées ci-dessus, le DTM présente de grands avantages à bien des égards. Si vous envisagez la prise en charge multilingue et la prise en charge du moteur multi-stockage, alors DTM est sans aucun doute votre premier choix
Installation
Il est très pratique d'installer le client dtm via Composer
composer require dtm/dtm-client
- N'oubliez pas de commencer. le serveur DTM lors de son utilisation Oh
Configuration
Fichier de configuration
Si vous l'utilisez dans le framework Hyperf, après avoir installé le composant, vous pouvez utiliser le vendor:publish
suivant > commande pour publier le fichier de configuration en un seul morceau ./config/autoload/dtm.php
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' => [],
],
];
配置中间件
在使用之前,需要配置 DtmClientMiddlewareDtmMiddleware
<?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();
}
}
Si vous l'utilisez dans un framework non-Hyperf, vous pouvez copier ./vendor /dtm/dtm-client/publish/dtm.php dans le répertoire de configuration correspondant.
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();
}
}
Configurer le middlewareAvant utilisation, vous devez configurer le middleware DtmClientMiddlewareDtmMiddleware
comme middleware global du serveur. Ce middleware prend en charge la spécification PSR-15 et peut être appliqué à divers frameworks qui la prennent en charge. spécification.
Pour la configuration du middleware dans Hyperf, veuillez vous référer au chapitre Documentation Hyperf - Middleware.
Utilisationdtm-client est très simple à utiliser. Nous fournissons un exemple de projet dtm-php/dtm-sample pour vous aider à mieux comprendre et déboguer.
Avant d'utiliser ce composant, il est également fortement recommandé de lire la documentation officielle du DTM pour une compréhension plus détaillée.
Le mode TCC est une solution de transaction flexible très populaire. Le concept de TCC se compose des acronymes de Try-Confirm-Cancel. Il a été publié pour la première fois par Pat Helland en 2007. Proposé dans un article intitulé "Life". au-delà des transactions distribuées : l'opinion d'un apostat".
Trois phases du TCCPhase d'essai : essayer d'exécuter, terminer tous les contrôles commerciaux (cohérence), réserver les ressources commerciales nécessaires (quasi-isolement) Phase de confirmation : si l'essai de toutes les branches est réussi, alors allez à l’étape Confirmer. Confirm exécute en fait l'activité sans aucun contrôle commercial et utilise uniquement les ressources métier réservées lors de la phase d'essai d'annulation : si l'un des essais de toutes les branches échoue, il passe à la phase d'annulation. Annuler libère les ressources métier réservées lors de la phase Try.
Si nous voulons mener une activité similaire à un virement interbancaire, le transfert (TransOut) et le transfert (TransIn) sont dans des microservices différents. Le diagramme de séquence typique d'une transaction TCC terminée avec succès est le suivant :
.
Exemples de code
Ce qui suit montre comment l'utiliser dans le framework Hyperf D'autres frameworks sont similaires
rrreeeMode Saga
Le mode Saga est l'une des solutions les plus connues dans le domaine des transactions distribuées et est également très. populaire dans les grands systèmes, apparu pour la première fois dans l'article SAGAS de 1987 par Hector Garcaa-Molrna et Kenneth Salem. Saga est une transaction finalement cohérente et flexible. Elle est également appelée transaction de longue durée et est composée d'une série de transactions locales. Après que chaque transaction locale met à jour la base de données, celle-ci publiera un message ou un événement pour déclencher l'exécution de la prochaine transaction locale dans la transaction globale Saga. Si une transaction locale échoue parce que certaines règles métier ne peuvent pas être satisfaites, Saga effectuera des opérations de compensation pour toutes les transactions qui ont été validées avec succès avant l'échec de la transaction. Par conséquent, lorsque l’on compare le mode Saga au mode TCC, il devient souvent plus difficile de mettre en œuvre une logique de restauration en raison du manque d’étapes de réservation de ressources.
Répartition des sous-transactions Saga- Par exemple, nous souhaitons effectuer une opération similaire à un virement interbancaire, en transférant 30 yuans du compte A au compte B. Selon le principe des transactions Saga, nous divisons la totalité transaction globale Pour les services suivants :
-
- Service TransOut, où l'opération sera effectuée pour déduire 30 yuans du compte A
- Service TransOutCompensate, annulez l'opération de transfert ci-dessus, c'est-à-dire que le compte A augmentera de 30 yuans
Service TransIn, ici le compte B sera augmenté de 30 yuans Service de compensation de transfert (TransInCompensate), l'opération de transfert ci-dessus sera annulée, c'est-à-dire que le compte B sera réduit de 30 yuans
La logique de l'ensemble de la transaction est :
Exécuter le transfert avec succès => Exécuter le transfert avec succès => La transaction globale est terminée
Si une erreur survient au milieu, comme une erreur de transfert vers le compte B, l'opération de compensation de la branche exécutée sera appelée, c'est-à-dire :
🎜Exécuter le transfert sortant avec succès => Échec de l'exécution du transfert entrant => Transfert exécuté avec succès en compensation => Compensation du transfert sortant exécuté avec succès => Annulation globale de la transaction terminée 🎜🎜Ce qui suit est un chronogramme typique d'une SAGA terminée avec succès 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();
}
}