gt-checksum v4.0.0 新功能解读系列文章(1):断点续传——大任务中断不再从头跑

在数据库迁移验收、跨版本升级等场景中,校验任务运行数小时是常态。一旦任务中断,过去只能从头重来。

gt-checksum v4.0.0 新增断点续传功能,让中断的任务可以从中断位置继续执行,大幅节省时间和资源。


一、功能简介

resume 是 gt-checksum v4.0.0 新增的核心参数,用于控制数据校验和修复任务的断点续传行为。

该参数同时适用于 gt-checksum (数据校验)和 repairDB(数据修复)两个工具。

参数说明

参数 默认值 可选值 说明
resume OFF OFF / ON / ASK 控制断点续传行为

三种模式的区别:

模式 行为
OFF 不启用断点续传(默认行为,与 v3.x 行为一致)
ON 发现未完成的进度文件时自动续传,无需人工干预
ASK 启动时提示用户选择是否从断点续传

使用方式非常简单,只需在配置文件 gc.conf 中添加一行:

ini 复制代码
resume=ON

二、功能作用及使用场景深入解读

2.1 为什么需要断点续传?

在生产环境中,数据库校验任务面临的挑战远比测试环境复杂:

场景一:大表校验耗时长

一个包含数百张表的数据库,其中几张大表可能各占数千万甚至上亿行记录,整个校验任务可能持续数十分钟甚至数十小时。

场景二:网络抖动或进程异常

校验过程中,如果遇到网络中断、服务器重启或进程被 OOM Killer 终止,任务会突然退出。在 v3.x 版本中,这意味着之前已完成的所有校验工作全部作废,必须从头开始。

场景三:维护窗口有限

运维人员可能需要在有限的维护窗口内完成校验,中途可能因故暂停。如果没有断点续传,暂停就等于放弃。

场景四:修复任务中断

使用 repairDB 执行修复 SQL 时,如果任务中断,已执行的 SQL 文件和未执行的文件混在一起,手动梳理哪些已执行、哪些未执行非常困难,且容易遗漏或重复执行。

2.2 断点续传如何工作?

gt-checksum 的断点续传依赖本地进度文件,核心机制如下:

进度文件

  • gt-checksum :保存在 result/ 目录下,文件名格式为 gt-checksum-progress-<RunID>.json
  • repairDB :保存在 <fixFileDir>/.repairDB-progress.json

进度文件采用原子写入策略(先写临时文件再 rename),确保在进程异常退出时不会产生损坏的进度文件。

gt-checksum 进度文件内容

进度文件记录了以下关键信息:

json 复制代码
{
  "run_id": "20260615103000",
  "start_time": "2026-06-15T10:30:00+08:00",
  "end_time": "2026-06-15T11:45:30+08:00",
  "config_hash": "...",
  "completed_tables": ["db1.orders", "db1.users"],
  "completed_table_results": [...],
  "table_progress": {
    "db1.logs": {
      "total_rows": 50000000,
      "chunk_size": 10000,
      "completed_chunks": [0, 10000, 20000, 30000],
      "completed_fixsql": [0, 10000, 20000],
      "checking_chunks": [30000],
      "source_rows": 50000000,
      "dest_rows": 50000000,
      "row_stats_cached": true,
      "exact_source_rows": 49876543,
      "exact_dest_rows": 49876543,
      "exact_row_stats_cached": true
    }
  },
  "status": "running"
}

其中几个关键字段:

字段 说明
completed_tables 已完成校验的表列表,续传时直接跳过
completed_chunks 已完成查询比对的 chunk 序号列表
completed_fixsql 已安全写完修复 SQL 的 chunk 序号列表
checking_chunks 中断时正在校验中的 chunk(未完成,需重新校验)
row_stats_cached 行数统计缓存标记,避免重复 COUNT(*)

续传判断逻辑

续传时,gt-checksum 会做以下判断:

  1. 表级别跳过 :已在 completed_tables 中的表直接跳过
  2. chunk 级别跳过 :对于未完成的表,从 completed_chunks 的连续前缀之后开始,跳过已安全完成的 chunk
  3. 修复 SQL 安全边界 :只有 completed_fixsql 边界内的 chunk 才会被跳过;checking_chunks 或仅完成查询但未确认写完 fixsql 的 chunk 会重新校验

数据安全保护

断点续传设计了多层数据安全保护机制:

  • fixsql 完整性校验:续传时会检查已生成的 fixsql 文件,截断最后一个不完整的事务块,保留已完整提交的部分
  • DELETE/INSERT 配对检查:若没有安全的 fixsql 续跑边界,程序会清理该表旧的 fixsql/rollsql 文件后从头重新生成,避免旧文件中 DELETE/INSERT 不成对导致数据被过度删除
  • 过期提醒 :若进度文件的 end_time 距当前超过 1 小时,续传前会提示用户确认,避免使用过早的校验进度导致结果不可信
  • 多文件冲突检测 :若同一结果目录存在多个 status=running 的进度文件,程序会输出候选列表并退出,需先清理无关进度文件

2.3 行数缓存:减少续传启动开销

在大规模场景下,查询表的行数(特别是精确行数 COUNT(*))本身就是一项耗时操作。断点续传模式下,gt-checksum 会将以下信息写入进度文件缓存:

  • 估算行数 (来自元数据查询 information_schema
  • 精确行数 (来自 COUNT(*) 全表扫描)

续传时直接读取缓存,无需重新查询数据库,显著减少大表场景下的续传启动时间。

2.4 repairDB 的断点续传

repairDB 的断点续传机制略有不同:

  • 进度文件记录每个 SQL 文件的执行状态success / failed
  • 续传时自动跳过已成功执行的 SQL 文件
  • 收到 Ctrl+CSIGTERM 时,停止调度新文件并等待已开始执行的文件完成,避免续传时重放半执行文件
  • 通过 .repairDB.lock 锁文件防止并发执行

重要提醒 :在断点续传模式下生成的修复 SQL 文件可能存在重复数据冲突(因为 chunk 范围可能重叠),手动执行 SOURCE SQL文件 可能会报错。建议使用 repairDB 执行修复,它会自动检测并处理重复数据冲突。


三、功能使用演示

3.1 基本配置

在配置文件 gc.conf 中设置 resume 参数:

ini 复制代码
# 启用自动断点续传
resume=ON

# 其他必要参数
checkObject=data
tables=db1.*
srcDSN=user:ENC[...]@tcp(10.0.0.1:3306)/db1
dstDSN=user:ENC[...]@tcp(10.0.0.2:3306)/db1
chunkSize=10000

3.2 gt-checksum 校验场景演示

场景一:正常运行 + 中断

bash 复制代码
# 第一次运行:校验进行中
$ gt-checksum -c gc.conf

Initializing gt-checksum
Reading configuration files
...
[CHECK] db1.orders: 5000/10000 chunks completed
[CHECK] db1.orders: 6000/10000 chunks completed
# 模拟异常中断(Ctrl+C 或进程异常退出)

此时进度文件已保存到 result/gt-checksum-progress-20260615103000.json,状态为 running

场景二:从断点续传

bash 复制代码
# 第二次运行:自动续传
$ gt-checksum -c gc.conf

Initializing gt-checksum
Reading configuration files

[RESUME] Found existing progress file: result/gt-checksum-progress-20260615103000.json
  Run ID: 20260615103000
  Started: 2026-06-15T10:30:00+08:00
  Completed tables: 3
  Completed list:
    db1.users
    db1.products
    db1.categories

Auto-resuming from checkpoint...
[SKIP] db1.users: already completed
[SKIP] db1.products: already completed
[SKIP] db1.categories: already completed
[RESUME] db1.orders: resuming from chunk 60000 (60% completed)
[CHECK] db1.orders: 7000/10000 chunks completed
...

场景三:进度过期提醒

如果中断时间较长(超过 1 小时):

bash 复制代码
$ gt-checksum -c gc.conf

Initializing gt-checksum
Reading configuration files

[RESUME] Found existing progress file: result/gt-checksum-progress-20260615103000.json
  Run ID: 20260615103000
  Started: 2026-06-15T10:30:00+08:00
  Completed tables: 3

[RESUME] 进度文件 end_time 为 2026-06-15T11:45:30+08:00,距离当前已超过 1 小时(3.2 小时)。
[RESUME] 期间源端或目标端数据可能发生变化,继续断点续传可能导致校验结果不可信。
是否继续从该断点续传校验?(y/n): _

输入 y 继续续传,输入 n 从头开始新的校验。

场景四:ASK 模式

ini 复制代码
resume=ASK
bash 复制代码
$ gt-checksum -c gc.conf

[RESUME] Found existing progress file: result/gt-checksum-progress-20260615103000.json
  Run ID: 20260615103000
  Started: 2026-06-15T10:30:00+08:00
  Completed tables: 3

Do you want to resume from the last checkpoint? (y/n): _

ASK 模式下,无论进度是否过期,每次启动都会询问用户。

3.3 repairDB 修复场景演示

ini 复制代码
resume=ON
bash 复制代码
# 第一次运行:修复进行中
$ repairDB -c gc.conf

[REPAIR] Processing: fix-orders-insert-001.sql ... OK
[REPAIR] Processing: fix-orders-delete-001.sql ... OK
[REPAIR] Processing: fix-users-insert-001.sql ...
# 模拟异常中断
bash 复制代码
# 第二次运行:自动续传
$ repairDB -c gc.conf

[RESUME] Found existing progress file: .repairDB-progress.json
[RESUME] Previously completed: 2 files
[SKIP] fix-orders-insert-001.sql: already executed successfully
[SKIP] fix-orders-delete-001.sql: already executed successfully
[REPAIR] Processing: fix-users-insert-001.sql ... OK
...

3.4 多进度文件冲突处理

如果 result/ 目录下存在多个 status=running 的进度文件:

bash 复制代码
$ gt-checksum -c gc.conf

gt-checksum: multiple status=running checkpoint progress files were found in result; resume cannot safely choose one automatically.
Please delete unrelated gt-checksum-progress-*.json files, or specify the runID to resume and retry.
Candidate files:
  - run_id=20260615103000 path=result/gt-checksum-progress-20260615103000.json start_time=2026-06-15T10:30:00+08:00 completed_tables=3
  - run_id=20260614090000 path=result/gt-checksum-progress-20260614090000.json start_time=2026-06-14T09:00:00+08:00 completed_tables=8

此时需要手动清理无关的进度文件后重试。


四、最佳实践及使用约束

4.1 最佳实践

1. 生产环境建议使用 resume=ON

对于大规模校验任务,建议在配置文件中默认启用 resume=ON,避免因意外中断导致重复工作:

ini 复制代码
resume=ON

2. 数据窗口校验场景使用 resume=ASK

如果不确定中断期间数据是否发生变化,使用 resume=ASK 模式,让工具在启动时提醒你做决定:

ini 复制代码
resume=ASK

3. 结合 chunkSize 优化断点粒度

断点以 chunk 为单位记录。chunkSize 越小,断点粒度越细,中断后需要重复校验的数据量越少,但会增加进度文件的大小和写入频率。建议根据表的大小选择合适的 chunkSize

表规模 建议 chunkSize
< 100 万行 5000 ~ 10000
100 万 ~ 1 亿行 10000 ~ 50000
> 1 亿行 50000 ~ 100000

4. 定期清理旧进度文件

正常完成的校验任务,进度文件状态会被标记为 completed。但如果任务异常退出后一直未续传,旧的 running 状态进度文件会留在磁盘上。建议定期检查并清理:

bash 复制代码
# 查看 result 目录下的进度文件
ls -la result/gt-checksum-progress-*.json

# 删除不再需要的旧进度文件
rm result/gt-checksum-progress-20260614090000.json

5. repairDB 续传时使用 repairDB 而非手动 SOURCE

断点续传模式下生成的修复 SQL 文件可能存在 chunk 范围重叠,导致重复数据冲突。repairDB 会自动检测并处理这类冲突,而手动执行 SOURCE SQL文件 可能会报错失败。

4.2 使用约束

1. 仅适用于静态数据场景

断点续传功能只适用于源端和目标端数据在任务期间保持静态的场景。如果业务仍在持续写入,中断期间数据可能已发生变化,续传后的校验结果可能不可信。此时建议重新执行完整校验。

2. 仅支持 checkObject=data

断点续传仅在数据校验模式(checkObject=data)下生效。struct(结构校验)、trigger(触发器校验)、routine(存储过程/函数校验)不支持断点续传。

3. 1 小时过期保护

若进度文件的 end_time 距当前超过 1 小时:

  • resume=ON 模式:会暂停并提示用户确认是否续传
  • resume=ASK 模式:同样会提示确认(与正常 ASK 行为一致)

这是为了防止使用过早的进度导致结果不可信。若确认数据未变化,选择 y 继续即可。

4. 进程退出时的行为

  • gt-checksum:进度文件会在每个 chunk 完成后更新,异常退出时最后完成的 chunk 之前的进度会被保留
  • repairDB :收到 Ctrl+CSIGTERM 后,会停止调度新的 SQL 文件,但会等待已开始执行的文件完成,确保不会出现"半执行"状态

5. 进度文件不会自动删除

正常完成的任务,进度文件状态会标记为 completed,但文件不会被删除。如果需要清理,需手动删除。resume=OFF 模式下,如果检测到 running 状态的进度文件,会发出告警并退出,防止误操作。

6. 配置一致性

续传时会使用当前的配置参数(如 chunkSizetables 等)。如果配置发生变化(如修改了 chunkSize),可能导致续传行为异常。建议使用与上次相同的配置文件进行续传。


五、总结

gt-checksum v4.0.0 的断点续传功能,从根本上解决了大规模校验任务"中断即重来"的痛点。通过本地进度文件记录表级别和 chunk 级别的完成状态,配合 fixsql 安全边界校验、行数缓存、过期保护等机制,确保续传后的校验结果准确可靠。

对于 repairDB,断点续传同样提供了文件级别的跳过机制,避免重复执行已成功的修复 SQL,结合 graceful shutdown 设计,确保不会出现半执行状态。

一句话总结resume=ON,让大任务中断不再从头跑。


相关阅读

相关推荐
南部余额6 小时前
Canal解决MySQL与Redis数据一致性问题
数据库·redis·mysql·canal·数据·数据同步
斯内普吖8 小时前
(开源)高校素拓分管理系统小程序实战指南 基于 Java + SpringBoot + uni-app + Vue + MySQL
java·spring boot·mysql·小程序·uni-app·开源
lazy H8 小时前
Spring Boot 连接 MySQL 失败怎么办?常见报错原因和解决方法总结
spring boot·后端·学习·mysql·spring
何极光8 小时前
MySQL 8.0详细安装教程(附下载地址)
数据库·mysql·adb
承渊政道9 小时前
【MySQL数据库学习】(MySQL复合查询)
数据库·学习·mysql·bash·database·数据库开发·数据库架构
Cx330❀9 小时前
【MySQL基础】详解MySQL数据类型:底层原理、越界测试与最佳实践
linux·开发语言·数据库·c++·mysql
Leon-Ning Liu9 小时前
MySQL数据恢复实践:binlog2sql数据追加
数据库·mysql
炘爚9 小时前
Linux——MySQL
linux·mysql
西凉的悲伤9 小时前
MySQL WITH RECURSIVE 详解
数据库·mysql·recursive·递归查询·with recursive