Skip to content

Repository files navigation

db-check 数据核对平台

目录

项目介绍

db-check 是一个面向数据迁移、数据同步和数据库运维场景的数据一致性核对平台。项目使用 Go 编写,提供 Gin HTTP API 和内置 Web 管理页面,可以集中管理数据源、核对任务、执行进度、差异明细和任务日志。

在数据库迁移或同步链路中,“两边行数相同”并不代表数据完全一致,仍可能存在记录缺失、目标端多数据、同一主键内容不同,以及过滤范围配置错误等问题。对大表直接编写临时 SQL 或导出文件人工比较,不仅耗时,也很难重复执行和追踪结果。db-check 将源端作为核对基准,读取源表和目标表的数据,通过主键或自定义唯一键匹配记录,给出以下结果:

  • 两端内容一致的记录数
  • 主键相同但字段内容不同的记录
  • 仅存在于源端的记录
  • 仅存在于目标端的记录
  • 两端总行数及任务、分片执行状态

平台只读取业务数据库,不会自动修改目标端数据。发现差异后,可以在页面查看和人工复核,也可以通过 API 生成参考修复 SQL,审核后再由使用者决定是否执行。

能解决的问题

  • 数据迁移验收:验证迁移前后的表数据是否完整,定位漏迁、重复或内容变化的记录。
  • 数据同步核验:检查同步链路两端在指定条件范围内是否一致,辅助排查同步延迟、过滤错误或异常中断。
  • 异构数据库比对:在 MySQL、Oracle、PostgreSQL、SQL Server、Doris、OceanBase 等不同数据库之间按公共字段进行核对。
  • 大表核对:按行数、数值范围或时间范围拆分子任务,结合并发控制降低单次全表处理压力。
  • 动态数据复核:对首次发现的差异再次按键读取,过滤核对过程中数据变化造成的瞬时差异。
  • 结果留痕:保存任务配置、状态、统计、差异明细、操作审计和任务日志,便于复盘。

适用场景

  • 数据库迁移、云迁移或机房迁移后的全量数据验收
  • MySQL 与 OceanBase、Doris 等系统之间的数据同步核对
  • Oracle、PostgreSQL、SQL Server 与其他数据库之间的异构迁移验证
  • 主备库、历史库、归档库或数仓明细表的阶段性一致性检查
  • 按日期、状态或业务条件核对部分数据
  • 需要对差异记录进行分页查看、人工复核和生成参考修复 SQL 的运维流程

不适用场景

  • 持续实时 CDC、数据复制或秒级监控;本项目是批量核对工具,不是同步引擎。
  • 自动比对和迁移表结构、索引、约束、存储过程等数据库对象;当前只核对表数据。
  • 无人审核的自动数据修复;系统只生成参考 SQL,不会自动执行。
  • 没有稳定主键或唯一业务键的逐行核对;此类表只能使用 count 模式,或先确定可靠的 custom_keys

当前管理页面支持 MySQL、OceanBase、Doris、Oracle、PostgreSQL 和 SQL Server。后端还包含 PolarDB、TDSQL-C 以及部分数据库类型别名。源端和目标端可以是不同类型的数据库,但字段名称、业务含义和可比较的数据表示需要兼容,建议在正式执行前先使用“检查配置”验证。

快速开始

  1. 在 MySQL 中创建元数据库,并执行 sql/init.sql
  2. db_check 同目录准备 config.ini,填写元数据库连接信息和 HTTP 端口。
  3. 编译并启动服务:go build -o db_check ./cmd && ./db_check
  4. 打开 http://127.0.0.1:8080/home,创建源端和目标端数据源并测试连接。
  5. 在“库任务”或“表任务”中填写核对配置,先执行“检查配置”,再提交任务并查看结果。

任务创建后由 Planner 按分钟调度;首次使用时可以先用少量数据和 count 模式验证元数据库、数据源和权限配置。

当前功能

  • 数据源管理:新增、编辑、删除、启停和连接测试
  • 库任务:选择多个同名表,批量生成表任务
  • 独立表任务:支持源表名与目标表名不同
  • 两种核对模式:逐行核对和仅行数核对
  • 按行数、数值区间或时间区间拆分子任务
  • 全局并发、单源并发和单表子任务并发控制
  • 暂停、恢复、终止、克隆和多种重跑方式
  • 自动复核与差异明细人工复核
  • 差异分页查看及修复 SQL 下载接口
  • 表任务日志查看和元数据库归档
  • 可选的请求头身份识别及 API 审计日志

数据库兼容性

管理页面可选择以下 db_type

db_type 核对引擎 列举表 页面连接测试 任务中的“库名”含义
mysql 支持 支持 支持 数据库名
oceanbase 支持 支持 支持 数据库名
doris 支持 支持 支持 数据库名
oracle 支持 支持 支持 Schema/Owner;数据源的 database_name 填 Service Name
pgsql 支持 支持 支持 Schema,通常填 public;数据源的 database_name 填实际数据库名
sqlserver 支持 支持 暂不支持 Schema,通常填 dbo;数据源的 database_name 填实际数据库名

后端核对引擎还识别 postgrespostgresqlmssql 别名,以及 MySQL 兼容的 polartdsqlc。这些值未全部出现在页面选项中,且连接测试接口也未全部支持,通常应使用表中的标准值。

任务创建接口要求源端和目标端的“库名”非空;对于 PostgreSQL 和 SQL Server,这个字段实际表示 Schema,因此需要显式填写 publicdbo 或业务使用的 Schema。

所有引擎均实现了元数据读取、流式取数、行数统计、分片和按键复核。实际可用性仍取决于数据库版本、字段类型、驱动兼容性和账号权限,上线前应使用页面中的“检查配置”进行预检。

核心概念

任务层次

库任务 check_db_tasks
  └─ 表任务 check_tb_tasks
       └─ 子任务 check_tb_sub_tasks
  • 库任务:保存一组公共配置。创建时,selected_tables 中每个准确表名会生成一个源/目标同名的表任务。
  • 表任务:当前调度器的最小执行单位。也可以脱离库任务单独创建,此时允许源表名和目标表名不同。
  • 子任务:表任务在准备阶段按切分范围生成;不配置切分字段时只生成一个子任务。

当前版本不会展开 order_{00..09} 之类的表名模式。库任务如需核对不同名表,应创建独立表任务。

核对模式

模式 行为 差异明细
default 按主键/自定义键读取两端数据,计算行摘要并比较 记录内容不一致、仅源端存在、仅目标端存在
count 分别执行行数统计 不记录逐行差异

default 模式要求源表存在主键,或配置逗号分隔的 custom_keys。自定义键必须能唯一标识记录,否则相同键会覆盖比较暂存数据,结果不可靠。

比较过程使用本地 Pebble 临时库完成无序数据归并,结束后清理临时目录;最终差异保存在 SQLite 中,因此运行目录需要预留足够磁盘空间。

字段配置

  • where_condition:不带 WHERE 关键字的 SQL 条件,最长 500 个字符,同时用于源端和目标端。
  • custom_keys:逗号分隔的自定义唯一键;留空时使用源表主键。
  • exclude_columns:逗号分隔的不参与内容比较的字段。键字段仍会用于记录匹配。
  • 目标表必须包含源表中未排除的字段。建议先执行“检查配置”,验证键、字段和分片范围。

分片配置

留空 split_column 时执行单个全表子任务。填写切分字段后,split_size 支持:

格式 含义 示例
<正整数>r 按大约指定行数寻找分片边界 1000000r
<正整数> 数值字段按固定步长切分 100000
<正整数>h 时间字段按小时切分 12h
<正整数>d 时间字段按天切分 7d
<正整数>m 时间字段按月切分 1m
<正整数>y 时间字段按年切分 1y

库任务可将 split_column 设置为 __pk1__(别名 primary_key_first),为每张表自动选择源表第一个主键字段。此时 split_size 留空会使用 1000000r;填写纯数字也会按行数处理并自动补 r

建议选择有索引、非空且分布合理的字段。页面只对配置了切分字段的运行中表任务显示“暂停”,因为暂停是等待当前子任务结束后停止后续分片。

自动复核

default 模式发现差异后,会再次按键读取两端数据,以过滤核对期间数据变化导致的瞬时差异:

  • max_recheck_times:最大自动复核轮数;小于等于 0 时关闭。
  • max_recheck_rows:待复核差异数上限;超过上限会跳过自动复核。
  • 自动复核通过的记录会从差异库移除,并累计到 recheck_pass_rows
  • 页面差异抽屉还支持对当前页或选中记录执行人工复核。

安装与启动

1. 环境要求

  • Go 1.25 或更高版本(以 go.mod 为准)
  • 一个 MySQL 元数据库
  • 到源端和目标端数据库的网络连通性及只读查询权限
  • 运行用户对程序目录有写权限,用于创建 data/logs/gorm.loghttp.log
  • 没有固定的 CPU、内存和磁盘最低值;资源需求取决于表大小、差异数量和并发设置

前端资源已包含在 web/,不需要 Node.js 或单独构建前端。

2. 初始化元数据库

先创建数据库,再执行完整建表脚本:

CREATE DATABASE db_check_meta CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
mysql -h 127.0.0.1 -P 3306 -u root -p db_check_meta < sql/init.sql

服务不会自动迁移表结构,已有环境升级时也需要人工核对并应用 sql/init.sql 中的最新字段和表。

secret_keysaccess_key='default' 的记录用于加密数据源密码。初始化脚本包含示例密钥,生产环境必须在录入数据源之前替换,并妥善备份;密钥变化后,原有密码将无法正常解密。

3. 配置服务

编辑可执行文件同目录下的 config.ini

http_port = 8080
concurrency = 8
source_concurrency = 1
http_auth_enabled = false

[db]
host = "127.0.0.1"
port = 3306
user = "db_check"
password = "请替换"
database = "db_check_meta"
配置项 默认值 作用
http_port 8080 HTTP 监听端口
concurrency 2 同时运行的表任务 worker 数
source_concurrency 1 同一个源数据源同时运行的表任务数
http_auth_enabled true 是否要求 API 请求携带身份请求头
[db] MySQL 元数据库连接信息

4. 编译并运行

go build -o db_check ./cmd
./db_check

程序启动后会自动切换到可执行文件所在目录,因此 config.iniweb/ 需要与部署后的 db_check 放在同一个目录层级;data/logs/ 会在运行过程中按需自动创建。

页面地址:http://127.0.0.1:8080/home

也可以使用仓库提供的简单管理脚本:

./admin.sh start
./admin.sh status
./admin.sh stop

admin.sh 通过进程名查找 db_check,不适合在同一主机运行多个同名实例。反向代理示例见 nginx_config.md

5. 发布 Release

仓库的 GitHub Actions 会在推送 v 开头的标签时自动运行测试,并为 Linux、macOS、Windows 的 amd64 和 arm64 生成完整安装包、SHA-256 校验文件及 GitHub Release。例如发布 v1.0.1

git tag -a v1.0.1 -m "Release v1.0.1"
git push origin main
git push origin v1.0.1

安装包包含可执行文件、Web 静态资源、初始化 SQL 和示例配置;Linux/macOS 包还包含 admin.sh 管理脚本。Windows 包中的程序名为 db_check.exe。首次启动前应修改包内的 config.ini。标签一旦推送便会触发公开发版,因此应先确保主分支代码和版本号正确。

6. 部署目录与资源

典型部署目录如下,data/logs/ 会在运行时自动创建:

db-check/
├── db_check
├── config.ini
├── admin.sh
├── web/
├── data/       # 结果 SQLite 和临时文件
├── logs/       # 表任务日志
├── gorm.log
├── http.log
└── running.log # 使用 admin.sh 启动时产生

大表默认模式会同时产生源端和目标端的临时 Pebble 数据,磁盘空间应按并发子任务和差异数据量预留。并发调高后,源库连接数、网络带宽、服务端内存和临时磁盘占用都会增加,应先在测试环境压测再调整。

使用流程

1. 创建数据源

在“数据源”页面创建源端和目标端连接:

  • 角色可选 sourcesinkboth
  • 新增时密码必填;编辑时密码留空表示保留原密码。
  • database_name 是建立连接时使用的数据库名或 Oracle Service Name。
  • extra 必须是 JSON 对象字符串;当前核对引擎不依赖旧文档中 Doris FE HTTP 地址等扩展参数。
  • SQL Server 当前不能通过“测试连接”按钮验证,但核对引擎本身已实现。

各数据库填写提示

类型 数据源 database_name 任务中的源库/目标库字段 说明
MySQL / OceanBase / Doris 实际数据库名 数据库名 表名按数据库查询
Oracle Service Name Schema/Owner Oracle 表名通常按 Owner 查询
PostgreSQL 实际数据库名 Schema,通常为 public 任务库名不能为空
SQL Server 实际数据库名 Schema,通常为 dbo 当前页面连接测试未接通

核对引擎只读取源端和目标端的表结构及数据,不会执行 INSERT、UPDATE 或 DELETE。源端、目标端账号至少需要连接、查询表数据和读取元数据的权限;元数据库账号则需要读写 sql/init.sql 创建的任务、数据源、日志和审计表。

2. 创建任务

有两种方式:

  1. 在“库任务”中选择源/目标数据源、库名和多个表。每个选中表立即生成一个同名表任务。
  2. 在“表任务”中直接创建独立任务。目标表名留空时默认使用源表名,也可以显式指定不同名称。

提交前使用“检查配置”确认:

  • 两端连接和表可访问;
  • 主键或自定义键有效;
  • 目标端未缺少待核对字段;
  • 分片参数可解析,并可查看预计子任务数。

启用的 pending 表任务由 Planner 每分钟整点扫描一次,新任务通常需要等待最多约 60 秒。当前查询只扫描最近 7 天创建的任务;超过 7 天的待执行任务不会被自动调度。

3. 查看状态

表任务有两个独立状态字段:

准备状态 prepare_phase

  • init:尚未准备
  • preparing:读取表结构并生成子任务
  • prepared:准备完成
  • failed:准备失败

执行状态 status

  • pending:等待 Planner 调度
  • queueing:已提交调度器
  • running:执行中
  • completed:执行完成
  • failed:执行失败
  • paused:已暂停
  • stopped:已终止

完成后,check_resultconsistentinconsistent;失败或终止时为 unknown。库任务状态和一致/不一致表数由其表任务实时汇总,并不是单独执行的准备状态机。

子任务状态 check_tb_sub_tasks.status

  • pending:等待表任务启动
  • running:正在读取和比较当前分片
  • completed:分片完成,统计结果已保存
  • failed:分片执行失败,可通过表任务重试失败分片
  • paused:收到暂停信号,尚未完成的分片等待恢复
  • stopped:收到终止信号,分片被强制停止

子任务的 check_result 同样会记录 consistentinconsistentunknown。表任务汇总结果来自所有子任务及其本地结果库。

4. 控制和重跑任务

  • 暂停:停止启动新的子任务,让已开始的子任务结束后进入 paused
  • 恢复:将暂停的表任务及其暂停子任务重置为 pending,等待下一轮调度。
  • 终止:取消正在执行的数据库操作,任务进入 stopped
  • 重新开始:删除现有子任务和 SQLite 结果,从头准备、执行。
  • 继续执行:保留已完成分片,仅继续尚未完成的分片,不重试失败分片。
  • 重试失败分片:保留已完成分片,将失败分片重置后继续执行。

库任务的暂停、恢复和终止会作用于其子表任务。只有完成、失败或终止的库任务可以删除;表任务只能在非排队、非运行状态编辑或删除。

5. 查看结果

表任务页面展示:

  • 源端/目标端行数
  • 一致行数
  • 内容不一致行数
  • 仅源端存在行数
  • 仅目标端存在行数
  • 执行耗时、错误信息、子任务和任务日志

点击差异数量可以分页查看键值和两端字段差异,也可以按子任务过滤。当前版本没有 CSV 导出功能。

结果与日志文件

所有相对路径均以可执行文件所在目录为基准:

路径 内容
data/<tb_task_id>/<source_table>.db 表任务的 SQLite 差异明细和摘要
data/<tb_task_id>/tmp/<sub_task_id>/ Pebble 比较暂存目录,正常结束后自动清理
logs/<tb_task_id>.log 表任务详细日志
running.log 使用 admin.sh start 时的进程标准输出/错误
http.log Gin HTTP 访问日志
gorm.log 元数据库 GORM 日志

表任务进入 completedfailedpausedstopped 后,完整任务日志还会写入元数据库的 check_tb_task_logs 表。

不要在任务运行中移动、删除或共享写入 SQLite/Pebble 文件。备份时应同时保留元数据库与 data/,否则页面无法读取历史差异。

日志和监控

查看任务日志

任务日志按表任务 ID 保存,可以直接查看运行过程:

tail -f logs/123.log
tail -n 100 logs/123.log
grep -i "error\|failed" logs/123.log

已结束的表任务还可以通过 GET /api/check-tb-tasks/:id/log 读取归档日志。http.log 用于排查接口请求,gorm.log 用于排查元数据库读写。

查看调度状态

curl 'http://127.0.0.1:8080/api/scheduler-stats'

返回值包括就绪队列长度、全局并发数、单源并发数、排队任务数、运行任务数以及按数据源划分的待执行数量。启用 HTTP 身份识别时,需要同时携带 X-User-ID 请求头。

建议关注

  • 长时间停留在 pendingqueueing 的任务
  • failed 任务及其 error_message
  • 源库连接失败、权限错误和目标表字段缺失
  • data/ 所在磁盘空间和 Pebble 临时目录清理情况
  • 源库连接数、查询耗时和线上业务负载

修复 SQL

修复 SQL 目前通过 API 按差异类别和分页下载,管理页面尚未提供入口:

curl -X POST 'http://127.0.0.1:8080/api/check-results/123/repair-sql' \
  -H 'Content-Type: application/json' \
  -d '{"diff_type":"source_more","page":1,"page_size":100}' \
  -o repair.sql

差异类型与生成语句:

  • source_more:生成 INSERT
  • target_more:生成 DELETE
  • diff:生成 UPDATE

接口只处理请求指定的一页,不会自动保存 SQL 到 data/。生成器使用通用 SQL 文本,没有完整覆盖各数据库的标识符、保留字和特殊字段类型规则;执行前必须人工审核,并建议先在测试环境验证。

HTTP API 概览

页面路由:

  • GET /home:主页面
  • GET /tb-sub-tasks:子任务页面
  • GET /static/*GET /components/*:静态资源

主要 API:

  • POST /api/ping:连接测试
  • POST /api/get-tables:列举数据源中的表
  • /api/data-sources:数据源 CRUD
  • /api/check-db-tasks:库任务 CRUD、克隆、暂停、恢复、终止
  • /api/check-tb-tasks:表任务 CRUD、克隆、恢复、重跑、日志
  • POST /api/check-tb-tasks/test-config:任务配置预检
  • GET /api/check-tb-sub-tasks:查询子任务
  • /api/check-results/:tb_task_id/*:摘要、三类差异、人工复核和修复 SQL
  • GET /api/scheduler-stats:调度队列与并发统计
  • /api/users:用户查询和更新

常用请求示例

查询已完成的表任务:

curl 'http://127.0.0.1:8080/api/check-tb-tasks?page=1&page_size=50&status=completed'

查询单个表任务的结果摘要:

curl 'http://127.0.0.1:8080/api/check-results/123/summary'

对指定差异记录执行人工复核:

curl -X POST 'http://127.0.0.1:8080/api/check-results/123/recheck' \
  -H 'Content-Type: application/json' \
  -d '{"diff_type":"diff","detail_ids":[1001,1002]}'

库任务的常用操作路径如下:

操作 方法和路径
创建库任务 POST /api/check-db-tasks
更新/删除库任务 PUT/DELETE /api/check-db-tasks/:id
克隆库任务 POST /api/check-db-tasks/:id/clone
暂停/恢复/终止库任务 POST /api/check-db-tasks/:id/{pause,resume,stop}
创建表任务 POST /api/check-tb-tasks
更新/删除表任务 PUT/DELETE /api/check-tb-tasks/:id
重跑表任务 POST /api/check-tb-tasks/:id/recheck
恢复暂停的表任务 POST /api/check-tb-tasks/:id/resume
查询子任务 GET /api/check-tb-sub-tasks
查询三类差异 GET /api/check-results/:id/{diff,source-more,target-more}

启用 http_auth_enabled 时,所有 /api 请求都需要由上游注入 X-User-ID;写请求还应由上游系统限制为有权限的操作人员。

身份识别与审计

鉴权模型

db-check 不提供登录页、密码校验、Token 签发或会话管理。鉴权由 Nginx、SSO、统一认证网关等可信上游系统完成,后端只负责读取上游注入的用户身份,并将身份用于任务创建人和审计记录。

请求链路如下:

浏览器
  │  登录凭证 / Cookie / Token
  ▼
反向代理或认证网关
  │  验证身份,通过后注入 X-User-ID
  ▼
db-check
  ├─ 静态页面和静态资源:直接提供
  └─ /api/*:身份识别 + HTTP 审计

启用 http_auth_enabled = true 时,所有 /api/* 请求必须包含非空的 X-User-ID,否则后端返回 401 Unauthorized

X-User-ID: 用户唯一标识(必填)
X-User-Name: 用户展示名(可选)

后端信任收到的 X-User-ID,不会自行验证 Cookie、JWT 或 Token。因此服务端口不能直接暴露给不可信客户端,否则客户端可以伪造请求头。生产环境应只允许可信反向代理访问后端,并在代理层覆盖客户端自行传入的 X-User-IDX-User-Name

配置开关

http_auth_enabled = true
  • true/api/* 先执行身份识别;缺少 X-User-ID 时返回 401。
  • false:关闭身份识别,API 直接放行;请求仍会写入审计日志,但没有关联用户 ID。

静态页面、/static/*/components/* 不经过身份识别中间件。是否限制页面访问,应由反向代理根据部署环境决定。

Nginx auth_request 示例

下面示例假设认证服务能够通过 2xx 表示认证成功,并在响应头中返回 X-User-ID。认证接口地址、登录跳转地址和后端地址需要替换为实际值:

# 认证子请求,不直接暴露给客户端
location = /internal/db-check-auth {
    internal;
    proxy_pass http://auth-server:8888/user/authInfo;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header Cookie $http_cookie;
    proxy_set_header Authorization $http_authorization;
    proxy_set_header X-Real-IP $remote_addr;
}

# API 需要认证,并将认证服务返回的用户 ID 传给 db-check
location /db-check/api/ {
    auth_request /internal/db-check-auth;
    auth_request_set $auth_user_id $upstream_http_x_user_id;
    auth_request_set $auth_user_name $upstream_http_x_user_name;

    proxy_set_header X-User-ID $auth_user_id;
    proxy_set_header X-User-Name $auth_user_name;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080/api/;
}

# 非 API 页面和静态资源按部署策略决定是否开放
location /db-check/ {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080/;
}

认证失败时,Nginx 通常返回 401403;如果需要跳转到统一登录页,应在 Nginx 中配置 error_page 或命名 location。后端本身不会跳转登录页。

用户记录

开启身份识别后,每个首次出现的 X-User-ID 会自动创建 users 记录;已有用户只更新 last_seen_atX-User-Name 只用于首次创建时填写 name,不会在每次请求中覆盖已有名称。

users 表主要字段:

字段 含义
user_id 上游传入的用户唯一标识,唯一索引
name 展示名
is_admin 管理员标记
last_seen_at 最近一次通过身份识别的时间

当前路由没有挂载 RequireAdmin 中间件,is_admin 目前不会自动限制数据源、任务或用户管理接口。也就是说,身份识别和管理员授权是两件事:前者由后端实现,后者目前应由反向代理、网关或后续路由权限改造负责。

HTTP 审计日志

通过身份识别的 /api/* 请求会继续经过 AuditMiddleware,并异步写入元数据库的 http_audit_logs 表。缺少 X-User-ID 而被身份中间件直接拒绝的请求会在更早阶段返回 401,不能依赖应用审计表记录这类请求;如需记录所有认证失败,应在 Nginx 或认证网关侧记录。记录内容包括:

  • user_id:身份识别得到的用户 ID
  • client_ip:客户端 IP
  • methodpathroute_patternquery_string
  • status_codesuccessduration_ms
  • request_body_summaryresponse_body_summary
  • error_messagecreated_at

请求和响应摘要最多保留 512 字节;只有 POSTPUTPATCH 请求会读取请求体摘要。/api/ping 的请求体固定记录为 [masked],避免把数据源密码写入审计表。审计写入采用异步数据库操作,接口响应不会等待日志 INSERT 完成;数据库故障时不应把审计记录视为绝对可靠的同步交易记录。

查询最近审计记录示例:

SELECT id, user_id, method, path, status_code, success, duration_ms, created_at
FROM http_audit_logs
ORDER BY id DESC
LIMIT 100;

常见问题

任务长时间处于 pendingqueueing

  • pending 任务由 Planner 每分钟整点扫描,刚创建后等待几十秒属于正常现象。
  • Planner 只调度启用状态且最近 7 天创建的 pending 表任务。
  • queueing 通常表示全局 worker 或该源数据源的并发额度已用满,可通过 /api/scheduler-stats 查看队列。

任务在 preparingfailed 停留

先查看表任务日志和 error_message,重点检查源/目标表是否存在、账号是否能读取元数据、表是否有主键、目标端是否缺少待核对字段,以及分片字段和 split_size 是否有效。

default 模式提示没有主键

default 模式要求源表有主键,或者在 custom_keys 中填写逗号分隔的唯一键。没有可靠唯一键时只能做 count 模式的行数核对;不要使用可能重复的普通字段作为自定义键。页面“检查配置”仍会读取并校验表元数据。

差异数量很多

确认源端和目标端使用了相同的 where_condition,并排除同步延迟、时区/类型转换、字符集差异和核对期间持续写入等因素。可以配置 max_recheck_times 进行自动复核,但超过 max_recheck_rows 的差异会被跳过,需要人工处理。

暂停、终止和重跑有什么区别

暂停会等待已启动的工作结束,终止会尽快取消正在执行的数据库操作。continue 保留已完成分片,retry 只重置失败分片,restart 会删除原有子任务和结果文件后重新执行。大表建议配置切分字段,以便分片级暂停和重跑。

查询结果时报结果文件不存在

结果文件位于 data/<tb_task_id>/。任务尚未完成、结果目录被手工删除,或使用 restart 重跑时清理了旧结果,都会导致历史差异无法查询。请不要在任务执行期间移动或删除 data/

为什么 SQL Server 可以核对但不能测试连接

SQL Server 的核对引擎、列举表和查询能力已经实现,但当前 /api/ping 的连接测试类型列表尚未包含 SQL Server。可以先用“检查配置”验证实际任务连接。

最佳实践

  1. 优先选择稳定唯一键:使用主键或真正唯一的业务键,避免用状态、时间等重复字段作为 custom_keys
  2. 给键和切分字段建索引:切分字段应尽量非空、分布均匀,避免用低基数字段导致大量扫描。
  3. 先行数、后逐行:迁移验收可先执行 count 模式确认范围和行数,再使用 default 模式定位具体差异。
  4. 固定核对范围:对持续写入的业务表使用明确的时间或业务条件,尽量采用左闭右开区间,避免相邻批次重复或遗漏。
  5. 控制并发:先以较低的 concurrencysource_concurrencysubtask_concurrency 验证负载,再逐步提高;优先保护生产源库。
  6. 为动态数据预留复核:数据核对期间无法停止写入时,配置合理的自动复核次数和行数上限,并人工检查未复核的大批量差异。
  7. 预留本地磁盘:默认模式会写入结果 SQLite 和临时 Pebble 数据,差异越多、并发越高,临时空间需求越大。
  8. 保存配套数据:备份历史结果时同时保存元数据库和 data/ 目录;只备份其中一部分无法完整恢复任务和差异。
  9. 先检查再执行:正式运行前使用“检查配置”确认连接、表结构、键、字段和预计分片数量。
  10. 修复前人工审核:生成的 SQL 只是参考脚本,不会自动执行,也不保证覆盖所有数据库方言和特殊字段类型。

当前未实现或限制

  • 没有定时执行计划或时间窗口;任务只有“创建后进入待执行队列”的模式。
  • 没有 QPS/带宽限流;只有并发数控制。
  • 不支持表名表达式或范围展开,只接受准确表名数组。
  • 不支持 CSV 差异导出。
  • 修复 SQL 只有下载 API,页面无入口,也不会自动执行 SQL。
  • 没有自动数据库迁移,元数据库表结构必须人工维护。
  • SQL Server 的连接测试接口尚未接通。
  • table_concurrency 不控制当前按表任务调度路径。
  • Planner 不会调度创建时间超过 7 天的 pending 表任务。

开发与验证

go test ./...
go vet ./...

项目入口为 cmd/db_check.go,HTTP 路由集中在 server/enter.go,数据库核对实现位于 engine/,核心执行流程位于 checker/,元数据库初始化脚本为 sql/init.sql

About

db-check 是一款跨数据库数据校验平台,用于验证源数据库与目标数据库之间的数据一致性。该工具支持MySQL、Oracle、Doris等多种数据库类型,提供全量校验和行数校验两种模式,适用于数据迁移、数据同步等数据一致性验证场景。 db-check 采用分片并发校验策略,能够高效处理亿级以上大表的数据比对。系统会自动记录不一致的数据差异,并支持生成修复SQL,帮助DBA快速定位和修复数据不一致问题。 该平台适用于数据迁移验证、主备数据一致性检查、历史数据完整性校验等场景,是数据库运维和数据治理的重要工具。

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages