1. 那些年我们踩过的数据坑

2019年某电商平台的促销活动中,用户发现购物车商品时有时无。经过排查,发现主从同步延迟导致读取到旧数据。这种数据不一致的情况就像超市货架标签和实际价格不符,虽然不会让服务器崩溃,但造成的业务损失可能比宕机更可怕。

2. 主从同步的运行真相

想象主从复制就像生产线上的传送带:

  1. 主库将变更事件写入binlog(如同工厂的生产日志)
  2. 从库IO线程实时搬运日志(像勤劳的运输工人)
  3. SQL线程在从库执行变更(相当于装配线上的操作工)

但传送带偶尔会卡住:网络波动会导致IO线程掉队,复杂事务可能让SQL线程处理不及,硬件故障更会让同步彻底中断。

3. 专业级体检工具pt-table-checksum

3.1 工具界的听诊器

Percona Toolkit中的pt-table-checksum就像数据库医生的听诊器,其工作原理堪称巧妙:

-- 创建校验表(类似体检记录表)
CREATE TABLE percona.checksums (
   db         CHAR(64)     NOT NULL,
   tbl        CHAR(64)     NOT NULL,
   chunk      INT          NOT NULL,
   chunk_time FLOAT            NULL,
   chunk_index VARCHAR(200)    NULL,
   lower_boundary TEXT          NULL,
   upper_boundary TEXT          NULL,
   this_crc   CHAR(40)     NOT NULL, -- 当前库的校验值
   this_cnt   INT          NOT NULL, -- 当前库的记录数
   master_crc CHAR(40)         NULL, -- 主库的校验值
   master_cnt INT              NULL,
   ts         TIMESTAMP    NOT NULL,
   PRIMARY KEY (db, tbl, chunk)
);

3.2 实战体检步骤

安装工具后执行检查(假设主库IP为192.168.1.100):

# 安装percona工具包
sudo apt-get install percona-toolkit

# 执行全库检查(类似全身扫描)
pt-table-checksum \
  --host=192.168.1.100 \
  --user=check_user \
  --password='SafePassword123!' \
  --databases=order_system \
  --no-check-binlog-format

# 检查结果输出示例
# TS ERRORS  DIFFS     ROWS  CHUNKS SKIPPED    TIME TABLE
# 04-14T11:45      0      12   985734      48       0  98.76 order_system.payment_records

3.3 检查报告解读指南

当DIFFS列出现数字时,需要进一步诊断:

-- 在从库执行差异查询(类似复查看片)
SELECT 
  db, 
  tbl, 
  chunk,
  this_cnt AS slave_cnt, 
  master_cnt AS master_cnt,
  this_crc AS slave_crc,
  master_crc AS master_crc 
FROM percona.checksums 
WHERE master_cnt <> this_cnt OR master_crc <> this_crc;

4. 自主研发的校验方案

4.1 存储过程校验法

适用小数据量的快速检查:

DELIMITER $$

CREATE PROCEDURE verify_orders()
BEGIN
  DECLARE m_crc VARCHAR(40);
  DECLARE s_crc VARCHAR(40);
  
  -- 主库计算校验值
  SELECT 
    COUNT(*) AS cnt,
    SHA1(CONCAT_WS('#',id,order_no,amount)) AS crc 
  INTO @m_cnt, m_crc 
  FROM orders;
  
  -- 从库计算校验值(需在从库执行)
  SELECT 
    COUNT(*) AS cnt,
    SHA1(CONCAT_WS('#',id,order_no,amount)) AS crc 
  INTO @s_cnt, s_crc 
  FROM orders;
  
  -- 结果比对
  IF @m_cnt != @s_cnt OR m_crc != s_crc THEN
    SELECT '数据不一致' AS result;
  ELSE
    SELECT '数据一致' AS result;
  END IF;
END$$

DELIMITER ;

4.2 定时任务组合拳

设置每日自动检查任务:

# 每天凌晨2点执行检查
0 2 * * * /usr/bin/pt-table-checksum --host=master_host --user=monitor_user \
--ask-pass --databases=critical_db --quiet > /var/log/checksum.log

# 结果邮件报警(需配置邮件服务)
grep -q "DIFFS" /var/log/checksum.log && mail -s "数据不一致报警" dba@example.com < /var/log/checksum.log

5. 关键场景生死局

5.1 钱要过手的时刻

金融交易系统中,账户余额表必须在主从库保持完全一致。某支付平台使用双活架构,曾在转账操作中出现主从差异导致重复扣款,靠pt-table-checksum发现1分钱的差额避免重大事故。

5.2 数据迁徙大作战

某游戏公司迁移数据时,使用如下校验流程确保完整性:

# 迁移完成后检查
pt-table-checksum --host=新主库IP \
--replicate-check-only \
--recursion-method=hosts \
--empty-replicate-table

6. 工具优缺点坦白局

pt-table-checksum优势矩阵

  • 智能分块:自动根据表大小选择检查粒度
  • 流量控制:默认1秒处理200个块,避免主库过载
  • 差异标记:发现不一致时会写入检查表

常见坑点备忘录

  • 权限陷阱:需要SELECT、SUPER、PROCESS权限
  • 字符集雷区:表字段使用不同字符集会导致误报
  • 延迟黑洞:建议设置--max-lag=2s参数

7. 避坑指南十诫

  1. 时间选择:避开业务高峰,选择凌晨执行检查
  2. 大表处理:超过1GB的表必须分块处理
  3. 索引检查:确保表有合适索引(如主键索引)
  4. 版本匹配:工具版本需与MySQL版本匹配
  5. 网络预检:提前测试主从间网络延迟
  6. 权限隔离:创建专用校验账号并限制权限
  7. 异常重试:对失败的任务设置自动重试机制
  8. 结果备份:保留历史检查记录方便追踪
  9. 报警分级:对核心表设置即时短信报警
  10. 修复预案:准备好数据修复脚本应对突发情况

8. 从体检到健康管理

某物流公司的实践值得参考:他们建立三层校验体系:

  1. 实时监控:在主从延迟超过5分钟时触发检查
  2. 每日巡检:对核心业务表进行全面检查
  3. 月度大盘点:使用mysqldump全量对比
-- 动态调整检查频率(根据表重要程度)
CREATE TABLE check_frequency (
  table_name VARCHAR(64) PRIMARY KEY,
  check_interval ENUM('hourly', 'daily', 'weekly'),
  last_check_time DATETIME
);