incubator-seata-go icon indicating copy to clipboard operation
incubator-seata-go copied to clipboard

[BUG] bugs detected by doubao

Open AlexStocks opened this issue 3 months ago • 3 comments

✅ 验证清单

  • [x] 🔍 我已经搜索过 现有 Issues,确信这不是重复问题

🚀 Go 版本

1.23

📦 Seata-go 版本

latest

💾 操作系统

🪟 Windows

📝 Bug 描述

要检测 incubator-seata-go 系统的潜在缺陷(含代码 bug),需结合历史修复记录(反映高频问题领域)和当前代码片段(暴露出现有风险)两方面分析,具体如下:

一、从历史修复记录看高频缺陷领域(潜在遗留风险)

从各版本 changes 文档的 bugfix 记录可知,以下系统在以下模块存在高频问题,需警惕后续类似场景的潜在风险:

1. 事务核心模块(AT/XA 模式)

  • 高频问题类型
    • AT 模式:undo log 生成/解析错误(如 #359 插入 undo log bug、#690 Jackson 解析器未找到、#509 SQLType 字段错误)、回滚逻辑异常(#368 回滚示例 bug、#672 AT 回滚 bug)、数据校验缺失(#366 新增回滚前校验)。
    • XA 模式:初始化 panic(#540)、提交/回滚失败(#562 提交 panic、#674 XA 回滚 bug)、数据库版本兼容性(#545 获取 DB 版本 bug)。
  • 潜在遗留风险
    • 复杂 SQL 场景(如子查询、特殊函数、JSON/空间类型)的 undo log 生成仍可能遗漏;
    • XA 模式在数据库断连、网络超时场景下的事务状态一致性(如悬挂事务、空回滚)未完全覆盖;
    • AT 模式的“数据校验-回滚”原子性不足,极端情况下可能出现脏回滚。

2. 通信与连接管理(Getty 组件)

  • 高频问题类型
    • Getty 初始化失败(#423、#424)、Session 自动关闭(#130)、心跳消息内存泄漏(#665 未回收 heartbeat response)。
  • 潜在遗留风险
    • 分布式环境下网络闪断时,Getty 重连逻辑可能存在重试风暴或死锁;
    • 远程调用的 future 对象未及时释放,仍可能引发内存泄漏(如非心跳类响应消息);
    • Session 关闭时资源(如连接、缓冲区)释放不彻底,导致文件句柄泄漏。

3. SQL 解析与处理

  • 高频问题类型
    • 特殊 SQL 语法支持不足(#724 缺失括号表达式、#780 TEXT 类型解码失败、#771 INSERT ON DUPLICATE UPDATE 大小写不匹配);
    • SQL 语句未正确关闭(#736)、表名大小写导致 lowkey 不一致(#781)。
  • 潜在遗留风险
    • 对非 MySQL 数据库(如 PostgreSQL、Oracle)的方言支持不完善(如特殊数据类型、语法关键字);
    • 复杂 SQL(如多表关联、嵌套子查询)的表名/字段提取错误,导致锁冲突或 undo log 无效。

4. 配置与初始化

  • 高频问题类型
    • undo log 配置文件加载错误(#418)、RM/TM 初始化流程混乱(#390 优化 RM 初始化)、全局事务上下文丢失(#472)。
  • 潜在遗留风险
    • 配置项依赖顺序错误(如事务超时时间在初始化后加载,导致生效延迟);
    • 多数据源场景下,RM 注册重复或资源绑定错误;
    • 全局事务上下文(如 Context)在 goroutine 切换时未正确传递(如异步回调中丢失)。

5. 并发与测试

  • 高频问题类型
    • 数据竞争(#326 fanout 测试竞争)、循环递归(#387 OpenConnector 死循环)、单元测试覆盖不足(#176 单测 bug)。
  • 潜在遗留风险
    • 共享资源(如配置缓存、连接池)未加锁,高并发下出现数据竞争;
    • 测试用例未覆盖“异常场景”(如网络超时、数据库宕机),导致线上隐藏 bug。

二、当前代码片段中的显性潜在 bug

从提供的代码文件片段中,可直接识别出以下未处理的风险点:

1. 事务提交忽略 beforeCommit 返回值(XA/AT 模式)

  • 代码位置
    • pkg/datasource/sql/tx_xa.go(XA 事务 Commit):
      func (tx *XATx) Commit() error {
          tx.tx.beforeCommit() // 未检查返回值
          return tx.commitOnXA()
      }
      
    • pkg/datasource/sql/tx_at.go(AT 事务 Commit):
      func (tx *ATTx) Commit() error {
          tx.tx.beforeCommit() // 未检查返回值
          return tx.commitOnAT()
      }
      
  • 问题描述beforeCommit 通常用于事务提交前的准备操作(如资源锁定、undo log 预检查),若其返回错误(如资源不足、检查失败),当前代码会直接忽略并继续执行 commitOnXA/AT,导致事务状态不一致(如未准备完成却强制提交,引发脏数据)。
  • 影响范围:XA/AT 模式下的事务提交可靠性。

2. SQL 解析遗漏 AST 节点类型(AT 模式执行器)

  • 代码位置pkg/datasource/sql/exec/at/base_executor.gotraversalArgs 方法:
    func (b *baseExecutor) traversalArgs(node ast.Node, argsIndex *[]int32) {
        if node == nil {
            return
        }
        switch node.(type) {
        // 仅处理 5 种 AST 节点类型,遗漏大量其他类型
        case *ast.BinaryOperationExpr: /* ... */
        case *ast.BetweenExpr: /* ... */
        case *ast.PatternInExpr: /* ... */
        case *ast.Join: /* ... */
        case *test_driver.ParamMarkerExpr: /* ... */
        // 未处理:UnaryExpr、FunctionCallExpr、SubqueryExpr 等
        }
    }
    
  • 问题描述: 该方法用于收集 SQL 中的参数索引(供 undo log 生成使用),但仅处理了 5 种 AST 节点类型。若 SQL 中包含未覆盖的节点类型(如 SELECT ABS(?) 中的 UnaryExprSELECT NOW() 中的 FunctionCallExpr),会导致 argsIndex 收集不完整,进而引发:
    • 参数绑定错误(如少传/错传参数);
    • undo log 生成异常(如无法还原原始数据)。
  • 影响范围:AT 模式下含复杂表达式的 SQL 执行。

3. 日志模块缺乏错误自处理(util/log)

  • 代码位置pkg/util/log/logging.goError 函数:
    func Error(v ...interface{}) {
        if log == nil {
            return
        }
        log.Error(v...) // 未处理 log.Error 自身的 panic
    }
    
  • 问题描述: 虽然检查了 log 是否为 nil,但未处理 log.Error 调用时可能发生的 panic(如 log 实例内部状态异常)。若 log 组件自身故障,会导致调用 log.Error 的业务逻辑(如事务失败回滚)崩溃,加剧故障影响。
  • 影响范围:全链路日志记录的可靠性,间接影响事务异常处理。

4. SQLHook 接口未定义错误处理规范(exec/hook)

  • 代码位置pkg/datasource/sql/exec/hook.goSQLHook 接口:
    type SQLHook interface {
        Type() types.SQLType
        Before(ctx context.Context, execCtx *types.ExecContext) error
        After(ctx context.Context, execCtx *types.ExecContext) error
    }
    
  • 问题描述: 接口定义了 Before/After 方法的错误返回,但未明确错误处理逻辑规范(如:Before 返回错误时是否中断 SQL 执行?After 错误是否需要重试?)。不同 SQLHook 实现可能对错误处理不一致,导致:
    • 安全钩子(如 SQL 黑白名单)失效(如 Before 报错却继续执行危险 SQL);
    • 事务钩子(如日志记录)异常时,事务状态不可追溯。
  • 影响范围:依赖 SQLHook 的扩展功能(如安全控制、审计日志)。

三、建议的风险排查与修复方向

  1. 事务核心模块

    • 补充复杂 SQL(子查询、特殊类型)的 undo log 生成测试;
    • 完善 XA 模式的“断连重试”“状态回查”逻辑,避免悬挂事务。
  2. Getty 通信

    • 检查所有远程调用的 future 对象是否及时回收,避免内存泄漏;
    • 增加 Session 异常关闭的监控告警(如文件句柄数、连接数)。
  3. SQL 解析

    • 补充 AST 节点类型覆盖(如 UnaryExprSubqueryExpr),并增加单元测试;
    • 适配多数据库方言,增加 PostgreSQL/Oracle 的兼容性测试。
  4. 代码缺陷修复

    • tx_xa.go/tx_at.gobeforeCommit 增加错误判断:
      if err := tx.tx.beforeCommit(); err != nil {
          return err
      }
      
    • base_executor.gotraversalArgs 补充未覆盖的 AST 节点处理;
    • log.Error 增加 defer recover() 防护,避免日志故障扩散。
  5. 测试覆盖

    • 补充高并发场景的压力测试(如 10k+ TPS 下的数据竞争检测);
    • 完善异常场景测试(网络超时、数据库宕机、配置错误)。

🔄 重现步骤

finded by doubao

✅ 预期行为

fix those errors

❌ 实际行为

nothing

💡 可能的解决方案

No response

AlexStocks avatar Sep 07 '25 03:09 AlexStocks

补充:Seata-go README.md 核心缺失模块与完善建议

基于现有 README.md 内容,结合分布式事务框架的用户使用场景与文档规范性,可补充以下关键信息,帮助用户更全面理解项目、降低上手成本并规避常见问题:

一、核心功能:支持的事务模式说明

现有文档仅提及 TM/RM/TC 角色,未明确 Seata-go 支持的事务模式(分布式事务核心特性),需补充每种模式的适用场景与核心逻辑:

1. 支持的事务模式

Seata-go 对齐 Seata-Java 核心能力,目前支持以下4种主流分布式事务模式,满足不同业务场景需求:

事务模式 核心原理 适用场景 优势 注意事项
AT 模式(Automatic Transaction) 基于 SQL 解析自动生成 undo/redo log,无侵入式事务控制,两阶段提交(一阶段本地提交+二阶段异步确认/补偿回滚) 非侵入式需求、SQL 操作场景(如电商订单-库存-支付链路) 开发无感知、性能优、适配主流关系型数据库(MySQL 优先) 需创建 undo_log 表(见下文配置)、不支持非 SQL 操作
XA 模式 基于数据库原生 XA 协议,强一致性事务(一阶段准备+二阶段提交/回滚) 强一致性需求、多数据库跨库事务(如金融核心业务) 完全遵循 ACID、数据库原生支持 性能较弱(长事务锁定资源)、需数据库支持 XA 协议
TCC 模式(Try-Confirm-Cancel) 业务层手动定义 Try(资源检查/预留)、Confirm(确认执行)、Cancel(补偿回滚)三阶段接口 非 SQL 操作场景(如调用第三方 API、缓存更新) 灵活性高、无锁阻塞 开发侵入式强、需手动处理幂等与空回滚
SAGA 模式 基于状态机的长事务解决方案,拆分事务为多个本地事务节点,失败时按逆序调用补偿节点 长事务场景(如跨天订单处理、物流状态流转) 支持超长事务、低资源占用 最终一致性、需手动设计补偿逻辑

二、环境依赖与前置条件

现有“如何运行”仅提供 go get 命令,缺少环境依赖说明,用户易因版本不兼容或前置配置缺失导致启动失败:

1. 基础环境要求

  • Go 版本:最低要求 Go 1.18+(依赖泛型、模块特性),推荐 Go 1.20+ 以保障性能与兼容性;
  • TC 服务器:需部署 Seata 服务器(TC 角色),版本兼容性如下:
    • Seata-go v2.0.0 兼容 Seata-Java TC v1.7.x / v2.0.x;
    • 低于 Seata-go v1.6.0 版本需匹配 Seata-Java TC v1.5.x 及以下;
  • 数据库支持:
    • 主流关系型数据库:MySQL 5.7+ / 8.0+(AT/XA 模式优先支持);
    • 实验性支持:PostgreSQL 12+(需手动适配方言配置);
    • 暂不支持 NoSQL 数据库(如 Redis、MongoDB)。

2. 前置配置(必做步骤)

(1)创建 undo_log 表(AT 模式必填)

AT 模式需在业务数据库中创建 undo_log 表(用于存储事务回滚日志),SQL 语句如下(以 MySQL 为例):

CREATE TABLE `undo_log` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `branch_id` bigint NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `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`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

(2)TC 服务器配置

需确保 TC 服务器已启动,并配置 registry.conf(注册中心)与 file.conf(事务存储模式),示例:

  • 注册中心:支持 Nacos / Eureka / ZooKeeper,如 Nacos 配置:
    registry {
      type = "nacos"
      nacos {
        serverAddr = "127.0.0.1:8848"
        namespace = ""
        group = "SEATA_GROUP"
      }
    }
    
  • 事务存储:支持 DB / Redis / File,生产环境推荐 DB 存储。

三、快速开始:极简代码示例

现有文档引导用户前往 samples 仓库,但 README 中加入极简示例可让用户快速理解核心用法(以 AT 模式为例):

1. 步骤1:初始化全局事务配置

在项目启动时初始化 Seata 配置(如 main.go):

package main

import (
  "github.com/apache/incubator-seata-go/pkg/client"
  "github.com/apache/incubator-seata-go/pkg/conf"
)

func init() {
  // 1. 配置 TC 地址(或通过配置文件加载)
  conf.Load(conf.WithFile("seata-config.yaml"))
  
  // 2. 初始化 Seata 客户端(TM + RM)
  if err := client.Init(); err != nil {
    panic("seata client init failed: " + err.Error())
  }
}

2. 步骤2:定义全局事务(TM 角色)

在业务入口函数中开启全局事务,包裹多个微服务调用:

import (
  "context"
  "github.com/apache/incubator-seata-go/pkg/tm"
)

// 全局事务入口:创建订单 -> 扣减库存 -> 扣减余额
func CreateOrder(ctx context.Context) error {
  // 1. 开启全局事务(生成 XID 并自动传播)
  globalTx, err := tm.BeginTx(ctx, tm.WithTimeout(60*1000)) // 事务超时 60s
  if err != nil {
    return err
  }
  defer func() {
    // 3. 全局事务提交/回滚(根据业务结果)
    if err != nil {
      _ = tm.RollbackTx(globalTx)
    } else {
      _ = tm.CommitTx(globalTx)
    }
  }()

  // 2. 调用各微服务(XID 会通过 Context 自动传播)
  if err = orderService.CreateOrder(globalTx, orderDTO); err != nil {
    return err
  }
  if err = stockService.DeductStock(globalTx, stockDTO); err != nil {
    return err
  }
  if err = accountService.DeductBalance(globalTx, accountDTO); err != nil {
    return err
  }

  return nil
}

3. 步骤3:本地事务接入(RM 角色)

在微服务的本地数据库操作中,通过 Seata 包装事务:

import (
  "context"
  "github.com/apache/incubator-seata-go/pkg/datasource/sql"
)

// 扣减库存(本地事务,自动注册为分支事务)
func (s *StockService) DeductStock(ctx context.Context, dto StockDTO) error {
  // 使用 Seata 包装的 DB 连接,自动关联全局事务
  db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/stock_db")
  if err != nil {
    return err
  }
  defer db.Close()

  // 本地 SQL 操作(自动生成 undo log,参与全局事务)
  _, err = db.ExecContext(ctx, 
    "UPDATE stock SET count = count - ? WHERE product_id = ? AND count >= ?",
    dto.DeductNum, dto.ProductID, dto.DeductNum,
  )
  return err
}

四、关键配置项说明

补充核心配置文件(如 seata-config.yaml)的关键参数,帮助用户快速适配环境:

seata:
  client:
    tm:
      rollback-retry-count: 3          # 全局回滚重试次数
      commit-retry-count: 3            # 全局提交重试次数
      timeout: 60000                   # 全局事务超时时间(ms)
    rm:
      report-retry-count: 5            # 分支事务状态上报重试次数
      table-meta-check-enable: true    # 是否开启表结构自动检查(AT 模式)
      lock:
        retry-count: 3                 # 锁冲突重试次数
        retry-interval: 1000           # 锁冲突重试间隔(ms)
  service:
    vgroup-mapping:
      my_test_tx_group: default        # 事务分组与 TC 集群映射(需与 TC 配置一致)
    grouplist:
      default: 127.0.0.1:8091          # TC 服务器地址(多个用逗号分隔)
  transport:
    type: tcp                          # 通信协议(默认 TCP)
    server: nio                        # TC 通信模式(NIO)
    heartbeat: true                    # 是否开启心跳检测

五、常见问题(FAQ)

补充用户初次使用时高频遇到的问题及解决方案,减少排查成本:

1. Q:XID 未传播到下游服务,导致分支事务未注册?

A:需确保以下两点:

  • 下游服务调用时,必须通过 context.Context 传递(Seata-go 基于 Context 携带 XID);
  • 避免使用 goroutine 异步调用(需手动通过 tm.TransferTx(ctx) 传递上下文)。

2. Q:AT 模式下报错“undo_log 表不存在”?

A:需在所有业务数据库中创建 undo_log 表(见上文 SQL),且表结构与数据库版本匹配(如 MySQL 8.0 需注意字符集为 utf8mb4)。

3. Q:TC 连接超时,报错“connect to 127.0.0.1:8091 failed”?

A:检查:

  • TC 服务器是否已启动,且端口 8091 未被占用;
  • 配置文件中 seata.service.grouplist 与 TC 实际地址一致;
  • 网络防火墙是否开放 TC 端口。

4. Q:TCC 模式下出现“空回滚”(Cancel 调用时无对应 Try 记录)?

A:需在 Cancel 接口中增加“幂等校验”:通过 XID + BranchID 查询本地事务状态,若未执行 Try 则直接返回成功。

六、版本兼容性说明

明确版本匹配关系,避免因版本不兼容导致功能异常:

Seata-go 版本 兼容 Seata-Java TC 版本 最低 Go 版本 主要特性
v2.0.0 v1.7.x / v2.0.x Go 1.18+ 新增 SAGA 模式、优化 AT 模式性能
v1.6.0 v1.5.x / v1.6.x Go 1.16+ 完善 XA 模式、支持 PostgreSQL 实验性适配
v1.0.0 v1.4.x Go 1.14+ 基础 AT/TCC 模式、MySQL 支持

注意:跨大版本使用时(如 Seata-go v2.0.0 对接 TC v1.4.x)可能存在兼容性问题,建议优先使用同大版本的 TC 服务器。

七、性能优化与监控建议

补充生产环境优化点与监控方案,满足高可用需求:

1. 性能优化建议

  • 连接池配置:增大数据库连接池(如 maxOpenConns: 100),避免 AT 模式下 undo log 写入阻塞;
  • 批量操作:对高频小事务(如批量订单创建),建议合并为单次全局事务,减少 TC 交互次数;
  • 锁优化:AT 模式下避免长事务(超时时间建议不超过 30s),减少行锁占用时间。

2. 监控集成

Seata-go 支持接入 Prometheus + Grafana 监控,核心指标包括:

  • 全局事务总数/成功数/失败数(seata_global_transaction_total);
  • 分支事务注册数/提交数/回滚数(seata_branch_transaction_total);
  • 事务平均耗时(seata_transaction_duration_seconds)。

配置方式:在 seata-config.yaml 中启用监控:

seata:
  metrics:
    enabled: true
    type: prometheus
    prometheus:
      port: 9898  # Prometheus 暴露端口

八、生态工具与资源

补充 Seata-go 相关生态工具,帮助用户提升开发效率:

  • 代码生成工具:Seata-go 提供 TCC 接口代码生成插件(seata-go-tcc-generator),自动生成 Try/Confirm/Cancel 模板代码;
  • 诊断工具:支持 Seata 诊断命令(如 seata-cli),可查询全局事务状态、手动清理异常 undo log;
  • IDE 插件:IntelliJ IDEA 插件(Seata Plugin)支持事务注解识别、配置文件高亮。

AlexStocks avatar Sep 07 '25 03:09 AlexStocks

please assign to me~

heliang666s avatar Sep 07 '25 03:09 heliang666s

Hi, I want to fix some issues related to the getty component.

Wangzy455 avatar Sep 07 '25 03:09 Wangzy455