MYSQL] binlog校验
binlog是什么?
binlog是mysql server层的日志, 一个非常重要的日志,记录用户的各种操作(changes). 默认启用.
binlog有啥用?
- 备份恢复: 可以用来恢复数据到任一时间点.(或者异常重启恢复)
- 高可用: 也可以用来搭建从库,集群等
- 审计: 查看数据的历史变更情况, 但是看不到执行者的IP,只能看到thread-id.
binlog怎么校验是否损坏?
这个是本文重要讨论的, 虽然mysqlbinlog
的--verify-binlog-checksum
选项就能校验binlog是否损坏(其实是写这个工具之前没发现这个参数…).
binlog损坏了怎么办?
凉拌
在讨论校验原理之前, 我们先简单看看binlog的结构:
- binlog由若干个event构成.
- 每个event由19字节的event_header(9字节)和event_body构成
- 第一个event为FORMAT_DESCRIPTION_EVENT, 记录的是binlog版本,mysql版本,checksum算法等信息.
- relay log和Binlog格式完全一样. 只不过binlog开头多了4字节的magic(b'\xfebin')
- event_header部分 信息为:
对象 | 大小 | 描述 |
---|---|---|
timestamp | 4 | 时间戳 |
event_type | 1 | event的类型 |
server_id | 4 | serverid |
event_size | 4 | 这个event大小(含event_header&checksum) |
log_pos | 4 | 结束位置的偏移量 |
flags | 2 | 一些flag |
整体如下
校验原理
在FORMAT_DESCRIPTION_EVENT中, 最后的信息是checksum_alg, 表示这个binlog是否有checksum位. 当然前提是参数binlog_checksum
的值为CRC32才行. 如果binlog_checksum
未设置校验的话, 是无法校验Binlog的. 我们这里就只讨论存在校验的情况.
有些情况可能会关闭binlog校验, 比如MGR
既然要校验, 那么肯定得每个event都校验,比较不可能文件写完之后才校验,那样就没得校验的意义了. 由于是server层实现的, 校验的算法通常就是crc32 (innodb使用的是crc32c).
那么这个校验值应该存储在哪呢? 最简单的就是存储在event结尾处. 出于兼容性考虑, event_header记录的大小/pos应该包含这4字节. 于是得到如下结构:
设计思路
既然知道该校验信息了, 那么就来设计个binlog的校验工具吧.
选语言: 我们使用python编写, 这样开发效率最高, 而校验主要是涉及到文件读取和crc32计算,这2者在编程语言之间差距不大(有时候感觉还挺快的)
兼容性: 使用者可能是python2或者python3环境, 所以我们需要考虑py2和py3的兼容性. 使用者可能是5.7, 8.0, 8.4环境, 所以还需要考虑mysql的兼容性. 还得同时支持binlog和relay log(就4字节的差)
使用: 由于功能单一, 不需要复杂的参数, 所以直接使用位置参数即可. 而使用者可能还想一次性校验多个文件, 所以还得考虑多个文件的情况, 而且文件可能有不存在的情况.
校验: 遇到坏的event之后, 就不应该继续校验了, 毕竟无法确定event的哪部分是损坏的, 也就无法确定下一个event的位置
说得比较简洁, 有些问题只有实际写的时候才会遇到, 比如: py2使用binascii.crc32校验的结果是有符号的(范围-2**31, 2**31-1
), 而py3使用binascii.crc32校验的结果是无符号的(范围0, 2**32-1
), 这种问题很多情况发现不了, 只有足够多的数据量(或者运气好)才能发现. 当然解决办法比较简单, 直接将结果&0xffffffff
即可变成无符号的整数
验证
我们就简单验证下效果
总结
- 在这个脚本写完之后,准备总结下的时候才发现其实官方也支持binlog的校验(
--verify-binlog-checksum
), 不过之前没有发现而已, 因为之前解析的时候有问题会直接报错的, 而这次没有报错出来, 就以为没得这个功能. 于是就重新写了一版(所以是v2) - 对于损坏的binlog,如果是从库,可以重建; 如果是主库呢?(只要数据提交了, 数据库没挂, 貌似就没得影响…)
转载于:https://mp.weixin.qq.com/s/FdtIGG0dFW8VxoOZiV18nQ
参考:
https://dev.mysql.com/doc/refman/8.0/en/binary-log.html
https://dev.mysql.com/doc/refman/8.0/en/group-replication-limitations.html
https://docs.python.org/zh-cn/2.7/library/binascii.html#module-binascii
相关脚本源码地址:
https://github.com/ddcw/ddcw/blob/master/python/check_binlog_v2.py