暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

[MYSQL] mysql checksum table原理浅析并使用python实现

原创 大大刺猬 2024-08-09
604

导读

前段时间, 做mysql切换的时候, 使用CHECKSUM TABLE来校验数据一致性. 源端校验时间比目标端多1倍. 而源端的innodb_buffer_pool_size恰好是目标端的1半, 于是就怀疑checksum table和buffer pool有关.

理论上应该是没得关系的, 两边配置(比如IO)等都不一样, 时间有差异也是正常的, 但就巧在这个一半上. 于是我们来稍微研究下.

使用gdb找到关键函数

虽然我们能猜到有check之类的关键词, 但这也直接使用grep -r还是太麻烦了. 我们使用一种通用的方法(之前varchar隐式转换的时候也用过)来找.

# 保证mysql只有一个连接 # 使用gdb打断点dispatch_command (echo -e "break dispatch_command\ncontinue"; while true;do echo 'step';done) | gdb -p `pidof mysqld` > /tmp/t20240809_dispatch_command.gdb.txt 2>&1 # mysql执行checksum table命令

等返回结果后, 我们就得到了checksum table的完整堆栈信息了. 大概1.8MB, 还是比较少的. 然后我们搜索关键词checksum就能找到对应函数了.(具体的哪行代码都有显示, 非常的方便)
image.png

mysql_checksum_table

接着我们直接打开源码(sql/sql_table.cc)分析这个函数即可
image.png
该函数比较简单, 我就直接列伪代码了. 不考虑表不存在,null等情况(这null也是一个坑…)

ha_checksum crc = 0; uchar null_mask = 256 - (1 << t->s->last_null_bit_pos); for (;;) { ha_checksum row_crc = 0; for (uint i = 0; i < t->s->fields; i++) { checksum_crc32(row_crc, f->field_ptr(), f->pack_length()); } crc += row_crc; } protocol->store((ulonglong)crc)

也就是遍历表的每行数据, 每行数据的每个字段做crc32, 然后再将每行的crc32加起来(&(2**32-1))即可.

checksum_crc32 调用 my_checksum.
my_checksum 调用crc32_z (zlib)

使用python实现checksum table

既然我们知道了原理, 那么我们就可以自己来实现checksum了. 结合ibd2sql就能快速(开并发)校验一张表的crc32值了. 但我们不整那么麻烦的. 就使用python简单模拟下即可 - _-

mysql构造数据并校验

create table db1.t20240809(name varchar(200) not null, url varchar(300) not null); insert into db1.t20240809 values('ddcw','https://github.com/ddcw'); insert into db1.t20240809 values('大大刺猬','https://www.modb.pro/u/17942'); insert into db1.t20240809 values('大大刺猬','https://cloud.tencent.com/developer/user/1130242'); checksum table db1.t20240809 ;

image.png

python 构造数据并校验

import zlib data = [ ['ddcw','https://github.com/ddcw'], ['大大刺猬','https://www.modb.pro/u/17942'], ['大大刺猬','https://cloud.tencent.com/developer/user/1130242'] ] crc32 = 0 for row in data: row_crc = 0 for col in row: row_crc = zlib.crc32(col.encode(),row_crc) crc32 += row_crc crc32 &= (2**32-1) print(crc32)

image.png

和mysql的CHECKSUM TABLE校验结果是一致的, 说明我们校验方法是正确的

总结

  1. mysql的checksum table是对数据一行行校验的, 也就是和innodb_buffer_pool_size关系不大. (其实直接修改buffer_pool多再校验一次,就能发现时间是一样的, 也能说明没关系的).
  2. checksum和行的读取顺序无关(加法和顺序无关)
  3. checksum列的顺序有关.
  4. checksum和存储引擎关系不大(server层实现的)
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论