用 pt-table-checksum 时,会不会影响业务性能?
成都创新互联公司服务项目包括措勤网站建设、措勤网站制作、措勤网页制作以及措勤网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,措勤网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到措勤省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!
实验
实验开始前,给大家分享一个小经验:任何性能评估,不要相信别人的评测结果,要在自己的环境上测试,并(大概)知晓原理。
我们先建一对主从:
然后用 mysqlslap跑一个持续的压力:
开另外一个会话,将 master 上的 general log 打开:
然后通过 pt-table-checksum 进行一次比较:
查看 master 的 general log,由于 mysqlslap 的影响,general log 中有很多内容,我们找到与 pt-table-checksum 相关的线程:
将该线程的操作单独列出来:
操作比较多,我们一点一点来说明:
这里工具调小了 innodb 锁等待时间。使得之后的操作,只要在 innodb 上稍微有锁等待,就会马上放弃操作,对业务影响很小。
另外工具调小了 wait_timeout 时间,倒是没有特别的作用。
工具将隔离级别调整为了 RR 级别,事务的维护代价会比 RC 要高,不过后面我们会看到工具使用的每个事务都很小,加上之前提到 innodb 锁等待时间调到很小,对线上业务产生的成本比较小。
RR 级别是数据对比的基本要求。
工具通过一系列操作,了解表的概况。工具是一个数据块一个数据块进行校验,这里获取了第一个数据块的下边界。
接下来工具获取了下一个数据块的下边界,每个 SQL前都会 EXPLAIN 一下,看一下执行成本,非常小心翼翼。
之后工具获取了一个数据块的 checksum,这个数据块不大,如果跟业务流量有冲突,会马上出发 innodb 的锁超时,立刻退让。
以上是 pt-table-checksum 的一些设计,可以看到这几处都是精心维护了业务流量不受影响。
工具还设计了其他的一些机制保障业务流量,比如参数 --max-load 和 --pause-file 等,还有精心设计的数据块划分方法,索引选择方法等。大家根据自己的情况配合使用即可达到很好的效果。
总结
本期我们介绍了简单分析 pt-table-checksum 是否会影响业务流量,坊间会流传工具的各种参数建议或者不建议使用,算命的情况比较多,大家都可以用简单的实验来分析其中机制。
还是那个观点,性能测试不能相信道听途说,得通过实验去分析。
很多时候需要把一个从库提升为主库,但对从库和主库的数据一致性不敢保证,这时我们就可以利用 pt-table-checksum来检查主库数据的一致性,如果存在不一致的数据,我们可以利用pt-table-sync来修复这些不一致的数据。
在主(master)上通过执行校验的查询对复制的一致性进行检查,对比主从的校验值,从而产生结果。
下面通过实际的例子来解释该工具如何使用:
主库(10.8.23.209)数据:
从库(10.8.23.208)数据:
从库(10.8.23.210)数据:
很明显主备数据不一致,我们使用工具来检测下:
校验命令参数解释:
校验结果字段解释:
好了,命令以及常用参数都介绍了,一起解释下上面执行的效果,通过DIFFS 是1 就可以看出主从的表数据不一致。怎么不一致呢? 通过指定—replicate=test.checksums 参数,就说明把检查信息都写到了checksums表中。
进入备库(10.8.23.208)中查看checksums表的信息:
进入备库(10.8.23.210)中查看checksums表的信息:
通过上面找到了这些不一致的数据,如何修复呢?利用另外一个工具 pt-table-sync。
高效的同步MySQL表之间的数据,他可以做单向和双向同步的表数据。他可以同步单个表,也可以同步整个库。它不同步表结构、索引、或任何其他模式对象。所以在修复一致性之前需要保证他们表存在。接着上面的复制情况,主库和从库的aaa表数据不一致,需要修复。
参数解释:
命令介绍完了,一起解释下执行的效果:通过(--print)打印出来了修复数据的sql语句,可以手动的去从行执行,让他们数据保持一致性。那能否直接执行?当然可以,通过(--execute)
没发现任何异常,然后检查主从数据的一致性:
主库(10.8.23.209)数据:
从库(10.8.23.208)数据:
从库(10.8.23.210)数据:
OK,数据已经保持一致了。
不过建议还是--print 打印出来的好,这样就可以知道那些数据有问题,可以人为的干预下。
不然直接执行了,出现问题之后不好处理。总之还是在处理之前做好数据的备份工作。
MySQL 主备的基本原理主备流程切换
在状态 1 中,客户端的读写都直接访问节点 A,而节点 B 是 A 的备库,只是将 A 的更新都同步过来,到本地执行。这样可以保持节点 B 和 A 的数据是相同的
当需要切换的时候,就切成状态 2。这时候客户端读写访问的都是节点 B,而节点 A 是 B 的备库。
M-S模式中, 为什么建议把备库设为readonly? 有时候一些运营类的查询语句会被放到备库上去查,设置为只读可以防止误操作; 防止切换逻辑有 bug,比如切换过程中出现双写,造成主备不一致 可以用 readonly 状态,来判断节点的角色。 把备库设置成只读了,还怎么跟主库保持同步更新呢?
因为 readonly 设置对超级 (super) 权限用户是无效的,而用于同步更新的线程,就拥有超级权限。
节点 A 到 B 这条线的内部流程是什么样的
下图画出的就是一个 update 语句在节点 A 执行,然后同步到节点 B 的完整流程图
备库 B 跟主库 A 之间维持了一个长连接。主库 A 内部有一个线程,专门用于服务备库 B 的这个长连接
一个事务日志同步的完整过程是这样的: 在备库 B 上通过 change master 命令,设置主库 A 的 IP、端口、用户名、密码,以及要从哪个位置开始请求 binlog,这个位置包含文件名和日志偏移量。 在备库 B 上执行 start slave 命令,这时候备库会启动两个线程,就是图中的 io_thread 和 sql_thread。其中 io_thread 负责与主库建立连接。 主库 A 校验完用户名、密码后,开始按照备库 B 传过来的位置,从本地读取 binlog,发给 B。 备库 B 拿到 binlog 后,写到本地文件,称为中转日志(relay log)。 sql_thread 读取中转日志,解析出日志里的命令,并执行。 binlog 的三种格式对比
三种格式分别是: statement row mixed
为了便于描述 binlog 的这三种格式间的区别, 创建并初始化一个表
mysql CREATE TABLE `t` ( `id` int(11) NOT NULL, `a` int(11) DEFAULT NULL, `t_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `a` (`a`), KEY `t_modified`(`t_modified`) ) ENGINE=InnoDB; insert into t values(1,1,'2018-11-13'); insert into t values(2,2,'2018-11-12'); insert into t values(3,3,'2018-11-11'); insert into t values(4,4,'2018-11-10'); insert into t values(5,5,'2018-11-09');
删除一行, 分析binlog
mysql delete from t /*comment*/ where a=4 and t_modified='2018-11-10' limit 1; 查询binlog命令: mysql show binlog events in 'master.000001'; 当 binlog_format=statement 时
binlog 里面记录的就是 SQL 语句的原文:
分析一下上图输出的结果: 第一行可以先忽略. 第二行是一个 BEGIN,跟第四行的 commit 对应,表示中间是一个事务; 第三行是真实的执行语句, 在delete命令前,还有一个use test命令, 是mysql自动添加的. 最后一行是一个 COMMIT, 包含一个xid. 如果使用statement格式, 记录到binlog 的是语句原文. 会有什么问题出现呢?
如果delete 带有 limit, 很可能出出现住主备数据库不一致的情况
在主库执行这条 SQL 语句的时候,用的是索引 a;而在备库执行这条 SQL 语句的时候,却使用了索引 t_modified
当 binlog_format= row 时:
与statement相比, begin 与 commit 是一致的, 但是row格式没有记录原文, 而是替换成了两个event, 粉笔是table_map 与 delete_rows
Table_map event,用于说明接下来要操作的表是 test 库的表 t; Delete_rows event,用于定义删除的行为。 使用mysqlbinlog工具分析解析binlog中内容 mysqlbinlog -vv data/master.000001 --start-position=8900;
解析结果:
server id 1,表示这个事务是在 server_id=1 的这个库上执行的。 每个 event 都有 CRC32 的值,这是因为参数 binlog_checksum 设置成了 CRC32。 Table_map event 显示了接下来要打开的表,map 到数字 226。现在我们这条 SQL 语句只操作了一张表,如果要操作多张表呢?每个表都有一个对应的 Table_map event、都会 map 到一个单独的数字,用于区分对不同表的操作。 在 mysqlbinlog 的命令中,使用了 -vv 参数是为了把内容都解析出来,所以从结果里面可以看到各个字段的值(比如,@1=4、 @2=4 这些值)。 binlog_row_image 的默认配置是 FULL,因此 Delete_event 里面,包含了删掉的行的所有字段的值。如果把 binlog_row_image 设置为 MINIMAL,则只会记录必要的信息,在这个例子里,就是只会记录 id=4 这个信息。 最后的 Xid event,用于表示事务被正确地提交了。 为什么会有 mixed 格式的 binlog?为什么会有 mixed 这种 binlog 格式的存在场景? 因为有些 statement 格式的 binlog 可能会导致主备不一致,所以要使用 row 格式。 但 row 格式的缺点是,很占空间。比如你用一个 delete 语句删掉 10 万行数据,用 statement 的话就是一个 SQL 语句被记录到 binlog 中,占用几十个字节的空间。但如果用 row 格式的 binlog,就要把这 10 万条记录都写到 binlog 中。这样做,不仅会占用更大的空间,同时写 binlog 也要耗费 IO 资源,影响执行速度。 所以,MySQL 就取了个折中方案,也就是有了 mixed 格式的 binlog。mixed 格式的意思是,MySQL 自己会判断这条 SQL 语句是否可能引起主备不一致,如果有可能,就用 row 格式,否则就用 statement 格式。 如何解决双M结构的循环复制问题解决两个节点间的循环复制的问题的逻辑 规定两个库的 server id 必须不同,如果相同,则它们之间不能设定为主备关系; 一个备库接到 binlog 并在重放的过程中,生成与原 binlog 的 server id 相同的新的 binlog; 每个库在收到从自己的主库发过来的日志后,先判断 server id,如果跟自己的相同,表示这个日志是自己生成的,就直接丢弃这个日志。 按照这个逻辑,如果我们设置了双 M 结构,日志的执行流就会变成这样: 从节点 A 更新的事务,binlog 里面记的都是 A 的 server id; 传到节点 B 执行一次以后,节点 B 生成的 binlog 的 server id 也是 A 的 server id; 再传回给节点 A,A 判断到这个 server id 与自己的相同,就不会再处理这个日志。所以,死循环在这里就断掉了。
方法一:如果你使用的是虚拟主机,可以用使用phpmyadmin来备份数据库。
1、登陆phpmyadmin。登陆后左边会出现数据库列表,单击要备份的数据库。
2、在弹出的页面中,右侧上部单击“导出”按钮,一般保持默认选项,最下面“另存为文件”,选择“ZIP压缩”,最后单击执行按钮。
3、弹出保存文件后,保存文件即可。