Spring CloudにおけるSeataの統合方法

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.confapplication.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のメトリクス(トランザクション成功率、ロック待ち時間など)を監視します。
    • アラートルールを設定します(例:トランザクションのタイムアウト、ロック競合)。

タグ: Seata Spring Cloud 分散トランザクション Nacos

5月25日 07:42 投稿