The mainstream distributed transaction processing scheme

In recent years, , With the widespread use of microservices , The business demands higher and higher distributed transaction processing capability of the system .

The early ones were based on XA Phase II of the protocol submission , Put the processing of distributed transactions in the database driver layer , It realizes no invasion to the business , But the locking time of data is very long , Low performance .

Now the mainstream TCC Transaction scheme and SAGA Business plan , Are based on the business compensation mechanism , Although there is no global lock , A high performance , But to some extent, it invades the business logic , It increases the development time and system maintenance cost of business developers .

burgeoning AT Transaction solutions , for example Seata and Seata-golang, Through the resource manager of the data source proxy layer RM Record SQL Rollback log , Submit with local transaction , Greatly reduce the data locking time , Good performance with little intrusion into the business . The disadvantage is that the supported language is relatively single , for example Seata Only support Java Language type microservices ,Seata-golang Only support Go Language type microservices .

In order to break through AT Transaction restrictions on business programming languages , Now the industry is going to DB Mesh Direction of development , By deploying transaction middleware in SideCar The way , Achieve the effect that any programming language can use distributed transaction middleware .

DBPack Is a database agent that handles distributed transactions , It can intercept MySQL Traffic , Generate the corresponding transaction rollback image , Through and with ETCD Coordinate the completion of distributed transactions , A high performance , And there is no invasion of business , It can automatically compensate SQL operation , Support access to any programming language .DBPack And support TCC Transaction mode , It can automatically compensate HTTP request . At present demo There has been a Java、Go、Python and PHP,TCC Of sample It's already on the way ,demo Examples can focus on dbpack-samples.

The latest version DBPack Not only support preprocessing sql sentence , And support text Type of sql.DBPack The latest version is also compatible php8 Of pdo_mysql Expand .Mysql The client is sending sql When executing the results , If there is no exception in the execution , The first packet sent is OKPacket, There is a flag bit in the package to identify sql Whether the request is in a transaction . As shown in the figure below

The contents of this package are :

07 00 00 //  front  3  Byte representation  payload  The length of is  7  Bytes 
01 // sequence Sequence number of response , front 4 Bytes together make up OKPacket Of header
00 // identification payload by OKPacket
00 // affected row
00 // last insert id
03 00 // Status flags
00 00 // warning Number

dbpack Previous versions set the flag bit to 0,java、golang、.net core、php 8.0 Previous mysql driver Can coordinate affairs correctly ,php 8.0 Of pdo driver The flag bit will be verified , therefore php 8.0 The above version is in use dbpack When coordinating distributed transactions , Will throw out transaction not active abnormal . The latest version has fixed this problem .

The figure below is specific DBPack Transaction flow chart .

The transaction flow is briefly described as follows :

  1. The client provides services to the aggregation layer DBPack Agent initiated HTTP request .
  2. DBPack Generate globally unique XID, Store in ETCD in . Note that the requested address and port point to DBPack, It does not directly point to reality API.
  3. If the global transaction is started successfully ( If it fails, the transaction will be ended directly ), Aggregation layer services can be provided through HTTP header(X-Dbpack-Xid) Get XID 了 . here , Aggregate service invokes service 1 And transmission XID.
  4. service 1 Get XID, adopt DBPack agent , Register branch transactions ( Generate BranchID Etc , And store it to ETCD).
  5. service 1 After the branch transaction of is registered successfully , Generate rollback image of local transaction , With local transactions commit.
  6. service 2 Conduct and service 1 The same procedure 4 and 5.
  7. Aggregation layer services are based on services 1 And the service 2 Result , Decide whether the global transaction is committed or rolled back , If it's a success , Then return to HTTP 200 to DBPack( except 200 Other status codes will be DBPack Consider it a failure ).DBPack to update ETCD The global transaction status in is global commit or rollback .
  8. service 1 And the service 2 Of DBPack, adopt ETCD Of watch Mechanism , Know whether the local branch transaction should be committed or rolled back ( If it is submitted , Delete the rollback log ; If it is rollback , Then rollback to the pre transaction image by rolling back the log ).
  9. After all branch transactions are committed or rolled back , Aggregation layer services DBPack The coroutine of will detect that the transaction has been completed , Will be taken from ETCD Delete XID and BranchID And other transaction information .

This article will be PHP Language as an example , Describe in detail how to use PHP docking DBPack Complete distributed transactions . When actually using other languages , The docking process is similar .

Use PHP docking DBPack Implementing distributed transactions

precondition

  • The business database is mysql database
  • The business data sheet is innodb type
  • The business data table must have a primary key

Step0: install ETCD

ETCD_VER=v3.5.3

# choose either URL
GOOGLE_URL=https://storage.googleapis.com/etcd
GITHUB_URL=https://github.com/etcd-io/etcd/releases/download
DOWNLOAD_URL=${GOOGLE_URL} rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
rm -rf /tmp/etcd-download-test && mkdir -p /tmp/etcd-download-test curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/etcd-download-test --strip-components=1
rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz /tmp/etcd-download-test/etcd --version
/tmp/etcd-download-test/etcdctl version
/tmp/etcd-download-test/etcdutl version

Step1: Create in the business database undo_log surface

undo_log Table is used to store rollback images of local transactions .

-- ----------------------------
-- Table structure for undo_log
-- ----------------------------
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
`ext` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_unionkey` (`xid`,`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Step2: Writing configuration files , docking DBPack

#  to update distributed_transaction.etcd_config.endpoints
# to update listeners Configuration item , Adjust the address and port of the actual aggregation layer service
# to update filters Configuration item , Configure the aggregation layer service API endpoint
vim /path/to/your/aggregation-service/config-aggregation.yaml # to update distributed_transaction.etcd_config.endpoints
# to update listeners Configuration item , Configure business database information , Include dbpack Port of agent
# to update data_source_cluster.dsn
vim /path/to/your/business-service/config-service.yaml

Step3: function DBPack

git clone [email protected]:cectc/dbpack.git

cd dbpack
# build on local env
make build-local
# build on production env
make build ./dist/dbpack start --config /path/to/your/config-aggregation.yaml ./dist/dbpack start --config /path/to/your/config-service.yaml

Step4: To configure vhost, monitor php Project port

With Nginx For example , The configuration is as follows

server {
listen 3001; # Exposed service port
index index.php index.html;
root /var/www/code/; # Business code root directory location / {
try_files $uri /index.php?$args;
} location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass order-svc-app:9000; # php-fpm port
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}

Step5: Write applications

aggregation service example

<?php

class AggregationSvc
{ public function CreateSo(string $xid, bool $rollback): bool
{
$createSoSuccess = $this->createSoRequest($xid);
if (!$createSoSuccess) {
return false;
}
$allocateInventorySuccess = $this->allocateInventoryRequest($xid);
if (!$allocateInventorySuccess) {
return false;
}
if ($rollback) {
return false;
}
return true;
} // private function createSoRequest(string $xid) ...
// private function allocateInventoryRequest(string $xid) ...
} $reqPath = strtok($_SERVER["REQUEST_URI"], '?');
$reaHeaders = getallheaders(); $xid = $reaHeaders['X-Dbpack-Xid'] ?? ''; if (empty($xid)) {
die('xid is not provided!');
} $aggregationSvc = new AggregationSvc(); if ($_SERVER['REQUEST_METHOD'] === 'POST') {
switch ($reqPath) {
case '/v1/order/create':
if ($aggregationSvc->CreateOrder($xid, false)) {
responseOK();
} else {
responseError();
}
case '/v1/order/create2':
if ($aggregationSvc->CreateSo($xid, true)) {
responseOK();
} else {
responseError();
}
break;
default:
die('api not found');
}
} function responseOK() {
http_response_code(200);
echo json_encode([
'success' => true,
'message' => 'success',
]);
} function responseError() {
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'fail',
]);
}

order service example

<?php

class OrderDB
{
private PDO $_connection;
private static OrderDB $_instance;
private string $_host = 'dbpack-order';
private int $_port = 13308;
private string $_username = 'dksl';
private string $_password = '123456';
private string $_database = 'order'; const insertSoMaster = "INSERT /*+ XID('%s') */ INTO order.so_master (sysno, so_id, buyer_user_sysno, seller_company_code,
receive_division_sysno, receive_address, receive_zip, receive_contact, receive_contact_phone, stock_sysno,
payment_type, so_amt, status, order_date, appid, memo) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,now(),?,?)"; const insertSoItem = "INSERT /*+ XID('%s') */ INTO order.so_item(sysno, so_sysno, product_sysno, product_name, cost_price,
original_price, deal_price, quantity) VALUES (?,?,?,?,?,?,?,?)"; public static function getInstance(): OrderDB
{
if (empty(self::$_instance)) {
self::$_instance = new self();
}
return self::$_instance;
} private function __construct()
{
try {
$this->_connection = new PDO(
"mysql:host=$this->_host;port=$this->_port;dbname=$this->_database;charset=utf8",
$this->_username,
$this->_password,
[
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_EMULATE_PREPARES => false, // to let DBPack handle prepread sql
]
);
} catch (PDOException $e) {
die($e->getMessage());
}
} private function __clone()
{
} public function getConnection(): PDO
{
return $this->_connection;
} public function createSo(string $xid, array $soMasters): bool
{
$this->getConnection()->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$this->getConnection()->beginTransaction();
foreach ($soMasters as $master) {
if (!$this->insertSo($xid, $master)) {
throw new PDOException("failed to insert soMaster");
}
}
$this->getConnection()->commit();
} catch (PDOException $e) {
$this->getConnection()->rollBack();
return false;
}
return true;
} private function insertSo(string $xid, array $soMaster): bool
{
// insert into so_master, so_item ...
}
} $reqPath = strtok($_SERVER["REQUEST_URI"], '?');
$reqHeaders = getallheaders(); $xid = $reqHeaders['Xid'] ?? ''; if (empty($xid)) {
die('xid is not provided!');
} if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($reqPath === '/createSo') {
$reqBody = file_get_contents('php://input');
$soMasters = json_decode($reqBody, true); $orderDB = OrderDB::getInstance();
$result = $orderDB->createSo($xid, $soMasters); if ($result) {
responseOK();
} else {
responseError();
}
}
} function responseOK() {
http_response_code(200);
echo json_encode([
'success' => true,
'message' => 'success',
]);
} function responseError() {
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'fail',
]);
}

Step6: Access the aggregation layer business interface

curl -X{HTTP Method} http://localhost:{DBPack Listening aggregation layer service port }/{ Aggregation layer services API endpoint}

Points of attention

  • Whether to use mysqli drive 、pdo_mysql drive , Or through mysql_connect() Connect to database (<=php5.4), stay start transaction; After the start , Subsequent business operations must be carried out on the same database connection .
  • DBPack adopt xid( Global transactions are unique ID) Propagate... In the context of a transaction , The business executed by the business database SQL In the sentence , Need to add xid notes , such DBPack According to xid Deal with the corresponding transaction . for example insert /*+ XID('%s') */ into xx ...;

Reference link

Author's brief introduction

Buhehe . Worked in Rakuten, Japan Rakuten CNTD, ren Application Engineer, be familiar with AT Business 、Seata-golang and DBPack.GitHub:https://github.com/bohehe

Use powerful DBPack Dealing with distributed transactions (PHP Use the tutorial ) More articles about

  1. elementary analysis SQL Server Implement a two-phase commit protocol for distributed transactions 2PC

    Not long ago, a new member of the team asked me a very important question web How does the service interface guarantee transactions . Because it involves cross database transactions , At that time, I just answered our current SOA No framework supports cross database transactions . Then I asked how the database cross database transaction is realized , I can only vaguely answer by impression ...

  2. Transaction isolation level and propagation mechanism ,spring+mybatis+atomikos Realize distributed transaction management

    1. Definition of transaction : A transaction is a collection of multiple operation units , Multiple unit operations are integral , Either the operation is unsuccessful , Either they all succeed . It must follow four principles (ACID). Atomicity (Atomicity): That is, the transaction is the smallest work order that cannot be divided ...

  3. Spring Detailed explanation of transaction isolation level and propagation mechanism ,spring+mybatis+atomikos Realize distributed transaction management

    Original description : This article is my original work , Not reproduced elsewhere , Please indicate the source of the transfer 1. Definition of transaction : A transaction is a collection of multiple operation units , Multiple unit operations are integral , Either the operation is unsuccessful , Either they all succeed . It must follow four principles (ACID). ...

  4. Distributed transactions ,EventBus Solution :CAP【 Chinese document 】

    Preface Many students want to be right CAP I want to have a detailed understanding of the mechanism and usage of , So I spent nearly two weeks writing this Chinese CAP file , Yes CAP Students who don't know can read this article first . This document is CAP The literature (Wiki), This article offers ...

  5. Message service framework (MSF) Implementation of distributed transaction three phase commit protocol in application instance

    One , Introduction to distributed transactions In the current Internet , In the upsurge of big data and artificial intelligence , Traditional enterprises are also impacted by this trend , Responding to the state “ Internet +” The strategic call of , Enterprises begin to migrate more and more applications from intranet to cloud and mobile terminals , Or isolate the previous IT ...

  6. Mycat Implementation of distributed transactions

    introduction :Mycat It has become a powerful open source distributed database middleware product . Facing the massive data transaction processing of enterprise application , Is the best open source solution at present . But if you want to keep data consistent across multiple machines , The more conventional solution is to introduce " Coordinate ...

  7. j2ee in spring Distributed transaction implementation and solution based on

    1 java Transaction type Java There are three types of transactions :JDBC Business .JTA(Java Transaction API) Business . Container transactions . Common container transactions such as Spring Business , Container transactions are mainly J2EE The application server provides ...

  8. 【 Distributed transactions 】 be based on RocketMQ Build a production level message cluster ?

    Reading guide At present, the systems of many Internet companies are moving towards micro service . The direction of distributed system is evolving , It brings a lot of benefits , It also brings some thorny problems , One of the most difficult problems is data consistency . In the early days, our software functions were in one process , The consistency of data can ...

  9. Distributed transaction framework Seata And EasyTransaction Comparison and thinking of architecture

    This article will compare Seata And EasyTransaction Some high-level design of two distributed transactions , I believe that we will get something . Seata Overview Seata( Name used before Fescar, Open source version GTS) Alibaba's open source distributed transaction framework , Its ...

  10. Instant messaging service framework (iMSF) Implementation of distributed transaction three phase commit protocol in application instance

    One , Introduction to distributed transactions In the current Internet , In the upsurge of big data and artificial intelligence , Traditional enterprises are also impacted by this trend , Responding to the state “ Internet +” The strategic call of , Enterprises begin to migrate more and more applications from intranet to cloud and mobile terminals , Or isolate the previous IT ...

Random recommendation

  1. 7 Container With Most Water_Leetcode

    Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). ...

  2. iOS Development ——UI Basics - Prompt box

    There are many kinds of prompt boxes , I don't say much nonsense , Go straight to the code One . Text prompt box The operation results are as follows : The code implementation is as follows : @interface ViewController () // Add method - (IBAction)add; ...

  3. Spring SimpleJdbcTemplate Querying examples

    Here are few examples to show how to use SimpleJdbcTemplate query() methods to query or extract data ...

  4. Digital Roots(hdoj1013)

    Problem Description The digital root of a positive integer is found by summing the digits of the int ...

  5. 【 Concrete mathematics Reading notes 】1.2 Lines in the Plane

    This section introduces the problem of plane division , namely n A straight line divides a plane into several areas at most (region). Problem description : "What is the maximum number Ln of regions defined ...

  6. Python In the middle of Base64 Encoding and decoding

    Base64 code Widely used in MIME agreement , As the transmission code of e-mail , The generated code is reversible , The last one or two may have “=”, The generated code is ascii character . advantage : Fast ,ascii character , It's incomprehensible to the naked eye : It's a long code , Very tolerant ...

  7. js Advanced object oriented programming

    Object oriented components <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...

  8. Spark With yarn-client Submit task error timeout ,Connection to 192.168.. /has been quiet forms while there are outstanding requests. Failed to send RPC.....

    The error message is as above , It's running FusionInsight Here's an example SparkPi, stay local It's OK in the environment , But if yarn-client The pattern gets stuck , then 120s After that, it's time-out , Actually yarn-cluster ...

  9. utilize eChart Draw a web page chart

    First , The best tutorial is here :eCchart eChart what is needed JS: echarts.min.js china.js echarts.js The page code is as follows : One . Chart <!DOCTYPE html> ...

  10. java Basics ----&gt; The multithreading synchronized( 6、 ... and )

    Here's to learn java On multithreading synchronized Usage of . I was too young to be serious , When you understand , You can only choose to grow old seriously . synchronized A simple example of One . synchronized To make in a way ...