Spring Cloudクライアントの統合
Spring Cloud環境でSeataを導入し、分散トランザクションを管理するためのステップは、依存関係の追加、Seataサーバーとクライアントの設定、データソースのプロキシ化、トランザクション境界の定義、そしてテスト検証です。以下に詳細な統合手順と設定を説明します。
1. 依存関係の追加
プロジェクトのpom.xmlにSeataクライアントの依存関係を追加します(推奨はspring-cloud-starter-alibaba-seataです)。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2021.0.4.0</version> <!-- 使用しているSpring Cloudのバージョンに合わせて選択 -->
</dependency>
または、Seataのコア依存関係を手動で追加することもできます。
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.7.1</version>
</dependency>
2. Seataクライアントの設定
application.ymlまたはapplication.propertiesファイルでSeataのパラメータを設定します。
seata:
enabled: true
application-id: my-spring-cloud-app # アプリケーションID
tx-service-group: tx_group_name # トランザクショングループ名
service:
vgroup-mapping:
tx_group_name: seata_cluster # Seata Serverのクラスタへのマッピング
grouplist: 127.0.0.1:8091 # Seata Serverのアドレス(複数インスタンスの場合はカンマ区切り)
registry:
type: nacos # レジストリタイプ
nacos:
server-addr: 127.0.0.1:8848 # Nacosサーバーのアドレス
config:
type: nacos # 設定センターのタイプ(オプション)
nacos:
server-addr: 127.0.0.1:8848
3. データソースのプロキシ設定
Seataはデータソースをプロキシすることでトランザクション管理を実現します。設定クラスで手動でプロキシするか、自動プロキシを有効にする必要があります。
- 手動プロキシ:
@Configuration public class SeataDataSourceConfig { @Bean public DataSourceProxy seataDataSource(DataSource dataSource) { return new DataSourceProxy(dataSource); } } - 自動プロキシ(Spring Boot 2.x以降):
application.ymlで有効にします。client: support: spring: datasource: autoproxy: true
4. undo_logテーブルの作成(ATモードの場合)
各ビジネスデータベースにundo_logテーブルを作成し、トランザクションのロールバックに使用します。
CREATE TABLE undo_log (
id BIGINT NOT NULL AUTO_INCREMENT,
branch_id BIGINT NOT NULL,
xid VARCHAR(128) NOT NULL,
context VARCHAR(128),
rollback_info LONGBLOB NOT NULL,
log_status INT NOT NULL,
log_created DATETIME NOT NULL,
log_modified DATETIME NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY ux_undo_log (xid, branch_id)
);
分散トランザクションの定義
サービスメソッドに@GlobalTransactionalアノテーションを追加して、グローバルトランザクションを開始します。
@Service
public class ProductOrderService {
@Autowired
private StockService stockService;
@GlobalTransactional(name = "placeOrder", rollbackFor = Exception.class)
public void placeOrder(ProductOrder productOrder) {
// 在庫サービスを呼び出す
stockService.decreaseStock(productOrder.getItemCode(), productOrder.getAmount());
// 注文を作成する
orderMapper.insert(productOrder);
// 例外をスローしてロールバックをテスト(コメントを外す)
// throw new RuntimeException("テスト例外");
}
}
name:トランザクション名(オプション)。
rollbackFor:ロールバックをトリガーする例外タイプを指定します(デフォルトはException.class)。
テストと検証
1. テストインターフェースの作成
@RestController
public class OrderApi {
@Autowired
private ProductOrderService productOrderService;
@RequestMapping("/place-order")
public String placeOrder() {
try {
ProductOrder productOrder = new ProductOrder();
productOrder.setItemCode(1L);
productOrder.setAmount(10);
productOrderService.placeOrder(productOrder);
return "注文が正常に作成されました。";
} catch (Exception e) {
return "注文の作成に失敗しました: " + e.getMessage();
}
}
}
2. トランザクションの動作確認
- 正常なフロー:
/place-orderエンドポイントを呼び出し、注文と在庫が同時に更新されるか確認します。 - 例外によるロールバック:
placeOrderメソッドで例外をスローし、注文と在庫がロールバックされるか検証します。
よくある問題と解決策
- Seataサーバーに接続できない:
registry.confとapplication.ymlのレジストリアドレスが一致しているか確認してください。- Seata Serverが起動しており、正しいポートでリッスンしていることを確認してください。
- データソースのプロキシに失敗する:
- データソースのプロキシが設定されているか(手動または自動)を確認してください。
undo_logテーブルが作成されており、フィールドの型が一致していることを確認してください。
- トランザクションが機能しない:
@GlobalTransactionalアノテーションが正しいメソッドに追加されているか確認してください。- トランザクショングループ名(
tx-service-group)がSeata Serverの設定と一致しているか検証してください。
本番環境での最適化に関する推奨事項
- 高可用性のデプロイ:
- 複数のSeata Serverインスタンスをデプロイし、Nacos/Eurekaレジストリを通じて負荷分散を実現します。
vgroupMappingを設定して、トランザクショングループを異なるクラスタにマッピングし、単一障害点を回避します。
- パフォーマンスチューニング:
store.db.maxConn(接続プールの上限)とstore.db.queryLimit(ページングクエリの制限)を調整します。- バッチリクエストの送信を有効にします:
transport.enableTmClientBatchSendRequest=true。
- 監視とアラート:
- Prometheus + Grafanaを統合してSeataのメトリクス(トランザクション成功率、ロック待ち時間など)を監視します。
- アラートルールを設定します(例:トランザクションのタイムアウト、ロック競合)。