最稳妥的同步方式是停写→导出→传输→导入→校验;禁用rsync同步运行中数据目录,仅可用其传输dump文件,并须md5校验与权限检查。

用 mysqldump + mysql 同步特定表最稳妥
直接用 rsync 同步 MySQL 数据目录(如 /var/lib/mysql/)是危险操作,数据库文件处于运行状态时,rsync 读到的可能是不一致的页缓存或未刷盘数据,恢复后大概率报错 Table 'xxx' doesn't exist 或 Incorrect information in file: 'xxx.frm'。真正可行的路径是导出再导入:停写、导出、传输、导入、校验。
实操建议:
- 目标表必须有主键或唯一键,否则增量同步无法定位变更行
- 导出时加
--single-transaction(InnoDB 表适用),避免锁全表;若用 MyISAM,必须先FLUSH TABLES WITH READ LOCK - 加上
--skip-triggers --skip-routines --skip-events,防止跨库触发器或存储过程干扰 - 导出命令示例:
mysqldump -h source_host -u user -p db_name table1 table2 --single-transaction > tables.sql
如何只同步新增和更新的行(非全量覆盖)
全量导入会清空目标表再重插,不适合大表或业务不能中断的场景。这时得靠应用层或 SQL 层做增量判断——MySQL 自身不提供“表级增量同步”命令,mysqldump 也不支持按时间戳或自增 ID 增量导出。
可行方案:
- 在源表加
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP字段,导出时用--where="updated_at > '2024-05-01 00:00:00'" - 导入前手动处理 SQL:把
INSERT INTO改成INSERT INTO ... ON DUPLICATE KEY UPDATE,需确保主键/唯一键存在 - 用
pt-table-sync(Percona Toolkit)自动比对并同步差异,但要求两端表结构完全一致,且需提前授权REPLICATION SLAVE权限 - 别依赖
rsync文件差异来“推断”数据差异——二进制日志格式、索引结构、页分裂都会让文件 diff 完全不可信
rsync 能用在哪?仅限静态文件传输环节
rsync 的合理位置只有一个:把导出的 tables.sql 文件从 A 机器传到 B 机器。它不该接触任何 MySQL 运行中的文件(.ibd、.frm、binlog 等)。
注意点:
- 传输前确认目标机磁盘空间足够,
tables.sql解压后体积通常是原文件 3–5 倍 - 用
rsync -avz --progress,加--delete很危险,误删目标端其他 SQL 文件就难回退 - 传输完成后务必校验 MD5:
md5sum tables.sql两边对比,网络传输可能静默损坏 - 别用
rsync同步到 MySQL 数据目录下再改权限试图“热替换”——MySQL 不认这种操作,启动直接拒绝
导入后必做的三件事
导入命令 mysql -h dest_host -u user -p db_name 执行完不等于同步完成。
必须立刻验证:
- 查行数:
SELECT COUNT(*) FROM table1;两边比对,但注意事务隔离级别可能导致临时不一致 - 抽样查关键字段:
SELECT id, updated_at FROM table1 ORDER BY id DESC LIMIT 5;看最新几条是否对得上 - 检查字符集:
SHOW CREATE TABLE table1;确保目标表CHARSET=utf8mb4且COLLATE一致,否则中文变问号
最容易被跳过的其实是权限和时区——如果源库用 NOW() 写时间,而目标库 time_zone 设为 +00:00,时间就会偏移 8 小时。这个坑没法靠 diff 发现,只能靠业务逻辑反推。











