Seata のインストールから始まる分散トランザクションのプロセス
導入
シータとは何ですか?
最新のアプリケーション開発では、分散システムがますます広く使用されています。ただし、システムの複雑さが増すにつれて、分散トランザクションを処理することがますます困難になります。これがシータが登場した背景である。Seata (Simple Extensible Autonomous Transaction Architecture) は、分散システムにおけるトランザクションの一貫性と調整の問題を解決するために設計されたオープンソースの分散トランザクション ソリューションです。
従来のモノリシック アプリケーションでは、通常、トランザクションを管理し、データの一貫性を確保するためにリレーショナル データベースが使用されます。しかし、分散システムでは、複数の独立したサービスが関与するため、トランザクション管理が複雑になります。分散トランザクションの要件は、データの一貫性を維持するために、関連するすべてのサービスが正常にコミットまたはロールバックされることです。
Seata は 2 つの主要なトランザクション モードを提供します。
-
AT モード (自動補償モード): AT モードでは、Seata は補償ロジックを手動で記述することなく、自動的にトランザクションを補償します。Seata は、トランザクションのすべての操作をグローバル トランザクションに配置し、各ブランチの try 操作を実行し、例外が発生したときに対応する補償操作を実行します。
-
TCC モード (2 フェーズ コミット モード): TCC モードでは、開発者は試行、確認、キャンセルの 3 つのフェーズのロジックを手動で記述する必要があります。TCC モードでは、Seata がグローバル トランザクションのコミットとロールバックを調整する責任を負い、各ブランチの試行、確認、キャンセルの操作は開発者によって実装されます。
Seata は、スケーラブルなレジストリとストレージのサポートも提供するため、さまざまなシナリオに適しています。
一般に、Seata は強力な分散トランザクション ソリューションであり、開発者が分散トランザクションの問題を解決し、分散システムにおけるデータの一貫性と信頼性を確保するのに役立ちます。Seata を統合することで、開発者は複雑な分散アプリケーションをより簡単に構築し、システムの安定性とパフォーマンスを向上させることができます。
Seata サーバーのインストール
Seata Server リリースをダウンロードする
最新の Seata Server リリースをSeata 公式 Web サイトからダウンロードし、指定したディレクトリに解凍できます。ソース バージョンとバイナリ バージョンがありますが、ここではダウンロードするバイナリ ファイルをインストールすることを選択します。私のバージョンは 1.7.0 (2023-07-11、推奨バージョン)
Seata の構成
ファイルを解凍する
ダウンロードしたファイルはzipファイルで、解凍すると上記のフォルダになります、デフォルトのフォルダ名はseataです。
Seataのymlファイルを設定する
seata/conf
ディレクトリに入ると、ここには 2 つの構成ファイルがあります。application.yml
任意に名前を変更し、application.example.yml
それをapplication.yml
メインの構成ファイルとして変更する必要があります。
ファイルを変更しますapplication.yml
。ここでは登録センターとして nacos を使用しているため、変更する必要がある場所は次のとおりです。
- シート:構成:タイプ
- シート:レジストリ:タイプ
- ストア:モード
- ストア:セッション:モード
- ストア:ロック:モード
- store:db データベースの構成が独自に変更されます
設定ファイル:
server:
port: 7091
spring:
application:
name: seata-server
logging:
config: classpath:logback-spring.xml
file:
path: ${
user.home}/logs/seata
extend:
logstash-appender:
destination: 127.0.0.1:4560
kafka-appender:
bootstrap-servers: 127.0.0.1:9092
topic: logback_to_logstash
# 这里是主要的配置文件
seata:
config:
# support: nacos 、 consul 、 apollo 、 zk 、 etcd3
type: nacos
nacos:
server-addr: 127.0.0.1:8848
# 如果在nacos上添加了命名空间,则配置命令空间ID
namespace:
# 配置分组
group: SEATA_GROUP
username:
password:
context-path:
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key:
#secret-key:
data-id: seataServer.properties
registry:
# support: nacos 、 eureka 、 redis 、 zk 、 consul 、 etcd3 、 sofa
type: nacos
preferred-networks: 30.240.*
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace:
cluster: default
username:
password:
context-path:
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key:
#secret-key:
server:
service-port: 8091 #If not configured, the default is '${server.port} + 1000'
max-commit-retry-timeout: -1
max-rollback-retry-timeout: -1
rollback-retry-timeout-unlock-enable: false
enable-check-auth: true
enable-parallel-request-handle: true
retry-dead-threshold: 130000
xaer-nota-retry-timeout: 60000
enableParallelRequestHandle: true
recovery:
committing-retry-period: 1000
async-committing-retry-period: 1000
rollbacking-retry-period: 1000
timeout-retry-period: 1000
undo:
log-save-days: 7
log-delete-period: 86400000
session:
branch-async-queue-size: 5000 #branch async remove queue size
enable-branch-async-remove: false #enable to asynchronous remove branchSession
store:
# support: file 、 db 、 redis
mode: db
session:
mode: db
lock:
mode: db
db:
datasource: druid
db-type: mysql
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true
user: mysql
password: mysql
min-conn: 10
max-conn: 100
global-table: global_table
branch-table: branch_table
lock-table: lock_table
distributed-lock-table: distributed_lock
query-limit: 1000
max-wait: 5000
metrics:
enabled: false
registry-type: compact
exporter-list: prometheus
exporter-prometheus-port: 9898
transport:
rpc-tc-request-timeout: 15000
enable-tc-server-batch-send-response: false
shutdown:
wait: 3
thread-factory:
boss-thread-prefix: NettyBoss
worker-thread-prefix: NettyServerNIOWorker
boss-thread-size: 1
設定ファイル config.txt を nacos にロードします
config.txt ファイルを変更する
config.txt
ファイルはseata/script/config-center
ディレクトリ内にあり、変更する必要がある場所は次のとおりです。
- ストア.モード=db
- ストア.ロック.モード=db
- ストア.セッション.モード=db
- store.db データベースの構成は、上記の yml ファイルと同じように独自に変更されます。
ナコスにロードする
ファイルseata/script/config-center/nacos
を実行するディレクトリを入力します。nacos-config.sh
sh nacos-config.sh -h 121.37.228.169 -p 8848 -g SEATA_GROUP -t 0af6e97b-a684-4647-b696-7c6d42aecce7 -u nacos -w nacos
- -h: Nacos IP アドレス
- -p: Nacos ポート番号
- -g: グループグループ名
- -t: ネームスペース ID (デフォルトでパブリックでない場合)
- -u: ユーザー名
- -w: パスワード
実行が完了したら、Nacos 構成管理にログインして、ロードされたデータを表示します。
Seata サービスを開始する
通常起動
seata/bin
ディレクトリに入り、次のコマンドを実行します。
sh seata-server.sh
ここで、起動時に異常事態に遭遇することがありますが、以下に起動時に遭遇した落とし穴をいくつか列挙します。に移動できます启动时遇到的坑
起動ログを表示する
私の Mac システムではログ ファイルを開くことができますが、他のシステムではシステムに応じてコマンドを実行するか、ファイルをseata/logs
表示するにはディレクトリに直接入力する必要がありますstart.out
。
open /Users/ddz/Downloads/seata/logs/start.out
起動が成功したことを示すログ出力アドレスが表示されます。
コンソールページを開く
コンソール ページでは、デフォルトのアカウント パスワードはseata/seataです。
始動時にピットに遭遇
Seata を導入する際に私が遭遇したいくつかの落とし穴を以下に示します。参考までに、それらの間に違いがある可能性があります。
${console.user.username} の値を解決できません
例外情報: 値「${console.user.username}」のプレースホルダー「console.user.username」を解決できませんでした。
解決策: 以前に別の名前に変更された yml ファイル内のすべての構成情報をconsole
現在のファイルにコピーする必要があります。 application.yml
1つ。ここでは、ログイン コンソール ページのアカウント パスワードを設定します。
${seata.security.secretKey} の値を解析できません
例外情報: 値 "${seata.security.secretKey}" のプレースホルダー 'seata.security.secretKey' を解決できませんでした
解決策: 以前に別の名前に変更された yml ファイル内のすべての構成情報をseata.security
現在の名前にコピーする必要がありますapplication.yml
1つ。
データベース接続の問題
例外情報: com.mysql.jdbc.Exceptions.jdbc4.CommunicationsException: 通信リンク障害
MySQL5.7 より前のバージョンではセキュリティが低く、誰でもデータベースに接続できてしまうため、正式版 5.7 ではプライバシー保護が強化されています。また、データベースのランダムな変更を防ぐために、デフォルトの useSSL = true 値が採用されています。バージョン 8.0 では、SSL は依然として保持されており、デフォルト値は true です。
解決策: データベース設定 URL の後に追加します&useSSL=false
。yml 設定ファイルと Nacos の設定リストを確認する必要がありますstore.db.url
。
Spring Boot プロジェクトに Seata を統合する
上記では、seata サーバーをローカルにインストールする方法と、Spring Boot プロジェクトへの Seata の統合を紹介しましたが、ここではデモを使用して紹介するだけであり、独自のビジネス ロジックに従って実装できます。
作業環境
- MySQL 5.7.28
- メイブン 3.5.4
- JDK1.8
- マイボット 3.4.1
- 動的3.4.1
クラウド、ブート、アリババ環境
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.6.RELEASE</spring-cloud-alibaba.version>
依存関係を追加する
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Mybatis -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<!-- 多数据源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<!-- Seata分布式事务 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
設定yml
server:
port: 7001
spring:
application:
name: ddz-user
cloud:
nacos:
discovery:
# 服务分组
group: ddz
server-addr: 121.37.228.111:8848
# 必须填命名空间的ID
# namespace: 9ebef975-dcc0-4430-9c63-1c62d8a86d82
datasource:
dynamic:
# 开启seata分布式事务
seata: true
strict: false
primary: master
datasource:
master:
url: jdbc:mysql://121.37.228.111:3306/ddz?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: ddz
password: ddz2023
local:
url: jdbc:mysql://127.0.0.1:3306/ddz?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: root
password: ddz2023
# MyBatis Plus配置
mybatis-plus:
# 搜索指定包别名
typeAliasesPackage: com.ddz.**.entity
# 配置mapper的扫描,找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*.xml
global-config:
db-config:
id-type: auto
configuration:
# 开启驼峰,开启后,只要数据库字段和对象属性名字母相同,无论中间加多少下划线都可以识别
map-underscore-to-camel-case: true
# Seata 配置
seata:
application-id: seata-server
# 是否启用数据源bean的自动代理
enable-auto-data-source-proxy: false
tx-service-group: default_tx_group # 必须和服务器配置一样
registry:
type: nacos
nacos:
# Nacos 服务地址
server-addr: 121.37.228.111:8848
group: SEATA_GROUP
# namespace: 9ebef975-dcc0-4430-9c63-1c62d8a86d82
application: seata-server # 必须和服务器配置一样
# username:
# password:
cluster: default
config:
type: nacos
nacos:
server-addr: 121.37.228.111:8848
group: SEATA_GROUP
# namespace: 9ebef975-dcc0-4430-9c63-1c62d8a86d82
service:
vgroup-mapping:
default_tx_group: default # 必须和服务器配置一样
disable-global-transaction: false
client:
rm:
# 是否上报成功状态
report-success-enable: true
# 重试次数
report-retry-count: 5
Seata をビジネス コードに統合する
mapper
2 つのデータ ソースに基づいて2 つのクラスを作成し、controller
それらをテストします。ここではテストの便宜上、ビジネス層を省略しています。
注釈を使用して@GlobalTransactional
グローバル トランザクションを管理する
AT (自動補償) モードと TCC (2 フェーズ コミット) モードをデモします。
AT(自動補正)モードを使用する
AT モードでは、Seata は手動で補償ロジックを記述することなく、トランザクションを自動的に補償します。まず、ある口座から別の口座に資金を転送し、トランザクションの一貫性を確保する単純な転送シナリオを示します。
- @GlobalTransactional アノテーションを追加する
@GlobalTransactional アノテーションを転送サービスのメソッドに追加して、グローバル トランザクションをマークします。
@Service
public class TransferService {
@GlobalTransactional
public void transfer(String fromAccount, String toAccount, double amount) {
// 扣除转出账户金额
deductAmount(fromAccount, amount);
// 增加转入账户金额
addAmount(toAccount, amount);
}
// 实现扣除金额逻辑
// ...
// 实现增加金额逻辑
// ...
}
- AT モードのテスト AT モード
でのトランザクション管理を検証するテスト ケースを作成します。
@RunWith(SpringRunner.class)
@SpringBootTest
public class TransferServiceTest {
@Autowired
private TransferService transferService;
@Test
public void testTransfer() {
// 假设从账户 A 转账 100 到账户 B
transferService.transfer("accountA", "accountB", 100.0);
}
}
テスト ケースを実行して転送が成功したかどうかを確認し、ログをチェックして Seata がトランザクションを自動的に補正したかどうかを確認します。
TCC (2 フェーズ コミット) モードを使用する
TCC モードでは、トランザクションが正しく実行されることを保証するために、試行、確認、キャンセルの 3 つのフェーズのロジックを手動で記述する必要があります。注文、在庫の差し引き、注文の作成という 3 つの段階を含む、簡単な注文作成シナリオを示します。
- TCC インターフェイスの実装
TCC インターフェイスを作成し、Try、confirm、Cancel の 3 つの段階のロジックを実装します。
public interface OrderTccService {
@GlobalTransactional
boolean createOrder(OrderDTO orderDTO);
@TwoPhaseBusinessAction(name = "orderTccService", commitMethod = "confirmOrder", rollbackMethod = "cancelOrder")
boolean tryCreateOrder(OrderDTO orderDTO);
boolean confirmOrder(OrderDTO orderDTO);
boolean cancelOrder(OrderDTO orderDTO);
}
- TCC ロジックの
実装 実装クラスに TCC ロジックを記述します。
@Service
public class OrderTccServiceImpl implements OrderTccService {
@Override
public boolean tryCreateOrder(OrderDTO orderDTO) {
// 预留库存逻辑
// ...
return true;
}
@Override
public boolean confirmOrder(OrderDTO orderDTO) {
// 确认创建订单逻辑
// ...
return true;
}
@Override
public boolean cancelOrder(OrderDTO orderDTO) {
// 取消创建订单逻辑
// ...
return true;
}
}
- TCC モードをテストする
TCC モードのトランザクション管理を検証するテスト ケースを作成します。
@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderTccServiceTest {
@Autowired
private OrderTccService orderTccService;
@Test
public void testCreateOrder() {
// 创建一个订单
OrderDTO orderDTO = new OrderDTO();
// 设置订单信息
// ...
orderTccService.createOrder(orderDTO);
}
}
テスト ケースを実行して注文が正常に作成されたかどうかを確認し、ログをチェックして TCC モードの試行、確認、キャンセルの各フェーズが正しく実行されたかどうかを確認します。
セアタが踏んだピットを一体化
ここでは、統合プロセス中に私が遭遇したいくつかの落とし穴を示します。参考までに、それらの間に違いがある可能性があります。
テーブル「ddz.undo_log」が存在しません
例外情報: プロセス接続プロキシ コミット エラー: テーブル 'ddz.undo_log' が存在しません。
解決策: データ ソース内の Seata に必要なログ テーブルを切り取り、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`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
利用可能なサービス「null」が見つかりません。レジストリ設定が正しいことを確認してください。
例外情報: この理由は、config.txt
nacos に Seata をロードしなかったためです。
解決策: コマンドを実行して、構成を Nacos 構成センターにロードします。上記を参照してください。把配置文件config.txt加载到nacos上
分散トランザクションが有効にならない
理由: 使用している複数のデータ ソースでは、デフォルトでは分散トランザクションdynamic
が有効になっていませんSeata
。
解決策: yml 設定ファイルdynamic
の下に設定を追加してseata: true
、分散トランザクションを有効にします。
動的データソースがプライマリ データソースを見つけることができません
理由:これはデータソース構成情報のエラーです。この例外の理由は、データベース接続 (URL) の接続を間違って書いてしまったためです。
解決策:datasource
次のデータ ソースの構成を再確認します。
通信リンク障害
理由: ここでの理由のほとんどは、MySQL が SSL 接続を行うかどうかを指定する必要があり、SSL 接続がデフォルトで有効になっているためです。
解決策: データベース接続構成 URL の後に追加するだけです&useSSL=false
。
要約する
分散システムが進化し続けるにつれて、分散トランザクションの分野も進化します。将来的には、さまざまなビジネス シナリオのニーズを満たすために、より分散されたトランザクション モデルとソリューションをさらに検討することができます。同時に、Seata は積極的なオープンソース プロジェクトとして、新しい機能と改善を導入し続ける予定であり、私たちは Seata コミュニティの更新に注意を払い、私たち自身の力を提供することができます。
さらに、 Seata に加えて、 、 、 などの他の分散トランザクション ソリューションもあります。TCC-Transaction
これらSAGA
のHSTC
ソリューションも、私たちが徹底的に調査し調査する価値があります。さまざまなビジネス シナリオに応じて、分散トランザクションの問題を解決するための最適なソリューションを選択できます。