跨服务的数据校验怎么做才又快又不漏?比总数够吗?全量比较要传多少数据?分桶校验和怎么省?增量、抽样各有什么坑?这篇用两个各有 100 万行的 MySQL,把这几种校验方法的发现能力和代价量出来。
A:count = 1000000, sum(amount) = 587881504;B:count = 1000000, sum(amount) = 587881504 —— count 和 sum 都一样,汇总校验认为“一致” 逐行哈希再异或(bit_xor(crc32(id|amount|status))):A = 2763208693,B = 3801738515 —— 不同,发现了
count 和 sum 对一加一减、只改状态这类错误完全看不出。
做法 | 用时 | 传输的数据量 | 报出的差异行 | 其中真差异 | 漏报 ----------------------------+--------------------------------+------------------------------------+--------+-------+--- 全量比较(两边所有行拉出来) | 3.6 s | 31.4 MiB | 50 | 50 | 0 分桶校验和(每 1000 行一个桶)+ 只拉有差异的桶 | 1.67 s(校验和 1.01 s + 下钻 0.66 s) | 1095 KiB(校验和 38 KiB + 下钻 1057 KiB) | 50 | 50 | 0 有差异的桶 34 个(共 1002 个桶);注入的差异 50 处。校验和在数据库内部算,只有每个桶的 (桶号, count, 哈希) 离开数据库
在库里按桶算 count 与行哈希,只传校验和,只下钻有差异的桶:用时和传输量都小得多,发现率不降。
差异类型(在 id 1~20000 的范围内) | count | sum(amount) | 行哈希 bit_xor | 行哈希 sum | 按 id 排序的行哈希串再 SHA-256 ------------------------+---------+-------------+-------------+---------+---------------------- 金额 +1 | 0 / 60 | 60 / 60 | 60 / 60 | 60 / 60 | 60 / 60 少一行 | 60 / 60 | 60 / 60 | 60 / 60 | 60 / 60 | 60 / 60 一加一减(抵消) | 0 / 60 | 0 / 60 | 58 / 60 | 60 / 60 | 60 / 60 状态被改(金额不变) | 0 / 60 | 0 / 60 | 60 / 60 | 60 / 60 | 60 / 60 count 只能发现行数变化;sum(amount) 发现不了“一加一减”和“只改状态”;行哈希 bit_xor 在“一加一减”上漏了 2 / 60 次(异或把两行的哈希变化互相抵消了;我的解释是 CRC32 是线性的,两处改动的比特差异模式相同时哈希差相同,这个解释没有单独验证);行哈希 sum 和按 id 排序的 SHA-256 链在这四类上都没有漏,代价是 SHA-256 链要排序、拼接,算起来最重
count、sum 管不了的情形,行哈希能管;bit_xor 偶尔漏(CRC 线性),sum 或 SHA-256 链更稳。
增量窗口 | 提交的改动 | 一直没被检查到的改动 | 漏报率 ----------------+-------+------------+------ 不重叠(只看上次检查开始之后) | 300 | 101 | 33.7% 窗口往前重叠 100 ms | 300 | 40 | 13.3% 窗口往前重叠 300 ms | 300 | 9 | 3.0% 窗口往前重叠 1000 ms | 300 | 0 | 0.0% 不重叠时,提交得比较晚的事务(持有超过一个检查周期的)会在检查器两次窗口之间漏掉;窗口往前重叠一段(要大于最长事务的持有时间)可以补上。更稳的做法是用提交顺序单调的位点(binlog 位点 / LSN / 自增版本号),而不是 updated_at
updated_at 不是提交时刻,事务提交晚的行会漏;窗口要重叠,或者用提交顺序单调的位点。
抽样行数 | 占总行数 | 抽到至少一处差异的试验数 | 实测发现概率 | 理论值(35 处差异) -------+-------+--------------+--------+------------ 1000 | 0.1% | 14 / 300 | 5% | 3% 10000 | 1.0% | 96 / 300 | 32% | 30% 100000 | 10.0% | 290 / 300 | 97% | 97% 500000 | 50.0% | 300 / 300 | 100% | 100% 差异只有总量的 0.0035% ~ 0.005% 时,抽样要抽到相当大的比例才有把握;而且按 A 的 id 抽样根本看不到 B 里“多出来”的行(那 15 处)。罕见的错误靠抽样找不出来
罕见错误要抽到很大比例才有把握,还看不到另一边多出来的行。