使用pt-table-checksum及pt-table-sync校验复制一致性详细介绍

一、简介

pt-table-checksum是percona-toolkit系列工具中的一个, 可以用来检测主、 从数据库中数据的一致性。其原理是在主库上运行, 对同步的表进行checksum, 记录下来。 然后对比主从中各个表的checksum是否一致, 从而判断数据是否一致。检测过程中以块为单位, 对于大的表可以区分为多个块, 从而避免锁表( 根据唯一索引将表切分为块)检测时会自动判断复制延迟、 master的负载, 超过阀值后会自动将检测暂停。

pt-table-sync,顾名思义,它用来修复多个实例之间数据的不一致。它可以让主从的数据修复到最终一致,也可以使通过应用双写或多写的多个不相关的数据库实例修复到一致。同时它还内部集成了pt-table-checksum的校验功能,可以一边校验一边修复,也可以基于pt-table-checksum的计算结果来进行修复。

二、工作原理

1. 单行数据checksum值的计算

计算逻辑与pt-table-checksum一样,也是先检查表结构,并获取每一列的数据类型,把所有数据类型都转化为字符串,然后用concat_ws()函数进行连接,由此计算出该行的checksum值。checksum默认采用crc32计算。

2. 数据块checksum值的计算

同pt-table-checksum工具一样,pt-table-sync会智能分析表上的索引,然后把表的数据split成若干个chunk,计算的时候以chunk为单位。可以理解为把chunk内所有行的数据拼接起来,再计算crc32的值,即得到该chunk的checksum值。

3. 坏块检测和修复

前面两步,pt-table-sync与pt-table-checksum的算法和原理一样。再往下,就开始有所不同:

pt-table-checksum只是校验,所以它把checksum结果存储到统计表,然后把执行过的sql语句记录到binlog中,任务就算完成。语句级的复制把计算逻辑传递到从库,并在从库执行相同的计算。pt-table-checksum的算法本身并不在意从库的延迟,延迟多少都一样计算(有同事对此不理解,可以参考我的前一篇文章),不会影响计算结果的正确性(但是我们还是会检测延迟,因为延迟太多会影响业务,所以总是要加上—max-lag来限流)。

pt-table-sync则不同。它首先要完成chunk的checksum值的计算,一旦发现主从上同样的chunk的checksum值不同,就深入到该chunk内部,逐行比较并修复有问题的行。其计算逻辑描述如下(以修复主从结构的数据不一致为例,业务双写的情况修复起来更复杂—因为涉及到冲突解决和基准选择的问题,限于篇幅,这里不介绍):

对每一个从库,每一个表,循环进行如下校验和修复过程。对每一个chunk,在校验时加上for update锁。一旦获得锁,就记录下当前主库的show master status值。

在从库上执行select master_pos_wait()函数,等待从库sql线程执行到show master status得到的位置。以此保证,主从上关于这个chunk的内容均不再改变。

对这个chunk执行checksum,然后与主库的checksum进行比较。

如果checksum相同,说明主从数据一致,就继续下一个chunk。

如果checksum不同,说明该chunk有不一致。深入chunk内部,逐行计算checksum并比较(单行的checksum的比较过程与chunk的比较过程一样,单行实际是chunk的size为1的特例)。

如果发现某行不一致,则标记下来。继续检测剩余行,直到这个chunk结束。

对找到的主从不一致的行,采用replace into语句,在主库执行一遍以生成该行全量的binlog,并同步到从库,这会以主库数据为基准来修复从库;对于主库有的行而从库没有的行,采用replace在主库上插入(必须不能是insert);对于从库有而主库没有的行,通过在主库执行delete来删除(pt-table-sync强烈建议所有的数据修复都只在主库进行,而不建议直接修改从库数据;但是也有特例,后面会讲到)。

直到修复该chunk所有不一致的行。继续检查和修复下一个chunk。

直到这个从库上所有的表修复结束。开始修复下一个从库。

三、校验测试

1.相关简介:

Mysql Version : 5.1.72

OS Version : CentOS release 6.4 (Final)

Master IP : 10.1.1.6

Slave   IP : 10.1.1.7

2.Master服务器安装Yum依赖包:

yum install perl perl-devel perl-Time-HiRes perl-DBI perl-DBD-MySQ

3.安装percona-toolkit工具包

wget http://www.percona.com/get/percona-toolkit.tar.gz

tar zxf percona-toolkit-2.2.13.tar.gz

cd percona-toolkit-2.2.13

perl Makefile.PL

make && make install

4.Master / Slave 数据库创建用户及授权

Create database pt CHARACTER SET utf8;

GRANT UPDATE,INSERT,DELETE,SELECT, PROCESS, SUPER, REPLICATION SLAVE ON *.* TO ‘checksums‘@‘10.1.1.6‘ identified by ‘Ll2g$26Dqm‘;

GRANT ALL ON pt.* TO ‘checksums‘@‘10.1.1.6‘ IDENTIFIED BY ‘Ll2g$26Dqm‘;

use pt;

CREATE TABLE IF NOT EXISTS 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 DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

PRIMARY KEY (db, tbl, chunk),

INDEX ts_db_tbl (ts, db, tbl)

) ENGINE=InnoDB;

5.校验(Master服务器运行)

pt-table-checksum --nocheck-binlog-format --nocheck-plan --nocheck-replication-filters --replicate=pt.checksums --set-vars innodb_lock_wait_timeout=120 --databases newtable -u‘checksums‘ -p‘checksums‘
-h10.1.1.6

#-h -u -p -P -S -d 连接信息

#--nocheck-replication-filters 检测中忽略mysql 配置参数binlog_ignore_db等。

#--nocheck-binlog-format 不检测日志格式

#--replicate 指定checksum 存储的db和表, 如test.checksum

# --chunk-size, --chunk-size-limit 用于指定检测块的大小。 可控性更强

# --ignore-databases/tables/column 跳出指定元素的过滤

# --lock-wait-timeout innodb 锁的超时设定, 默认为1

# --max-load 设置最大并发连接数

# --replicate-check-only 只输出数据不一致的信息。

# --help 有这个就行了, 以及其他的详见文档。

备注:--no-check-binlog-format 忽略检查binlog格式,否则会报错,默认会去检查statement模式,一般我们都用row模式

TS :完成检查的时间。

ERRORS :检查时候发生错误和警告的数量。

DIFFS :0表示一致,1表示不一致。当指定--no-replicate-check时,会一直为0,当指定--replicate-check-only会显示不同的信息。

ROWS :表的行数。

CHUNKS :被划分到表中的块的数目。

SKIPPED :由于错误或警告或过大,则跳过块的数目。

TIME :执行的时间。

TABLE :被检查的表名。

备注:主要观察DIFFS列,标识差异数。

6.查看差异(Slave库运行)

select db, tbl, sum(this_cnt) as total_rows, count(*) as chunks

from checksums

where ( master_cnt <> this_cnt OR master_crc <> this_crc OR isnull(master_crc)
<> isnull(this_crc) )

group by db, tbl;

7.复制,消除差异(Master服务器运行)

假设newtables数据库tb1表存在差异

i.自动消除差异(不推荐)

pt-table-sync --print --execute --sync-to-master h=10.0.0.7,P=3306,u=checksums,p=‘checksums‘ --databases=newtables --tables=tb1

ii.打印出sql语句,人工干预到Slave库执行(推荐)

pt-table-sync --print --sync-to-master h=10.0.0.249,P=3306,u=checksums,p=‘checksums‘ --databases=newtables --tables=tb1

pt-table-sync --print --sync-to-master h=10.0.0.249,P=3306,u=checksums,p=‘checksums‘
--replicate pt.checksums

#--sync-to-master :指定一个DSN,即从的IP,他会通过show processlist或show slave status 去自动的找主。

#--replicate :指定通过pt-table-checksum得到的表,这2个工具差不多都会一直用。

#--print :打印,但不执行命令。

#--execute  :执行命令。

备注:Slave需要授权主库Drop 和Create Temporary Tables权限

8.检验

重新执行一次pt-table-checksum,查看是否还存在差异。

四、注意事项

1.采用replace into来修复主从不一致,必须保证被replace的表上有主键或唯一键,否则replace into退化成insert into,起不到修复的效果。这种情况下pt-table-sync会采用其他校验和修复算法,但是效率非常低,例如对所有列的group by然后求count(*)(表一定要有主键!)。

2.主从数据不一致需要通过replace into来修复,该sql语句必须是语句级。pt-table-sync会把它发起的所有sql语句都设置为statement格式,而不管全局的binlog_format值。这在级联A-B-C结构中,也会遇到pt-table-checksum曾经遇到的问题,引起行格式的中继库的从库卡库是必然。不过pt-table-sync默认会无限递归的对从库的binlog格式进行检查并警告。

3.由于pt-table-sync每次只能修复一个表,所以如果修复的是父表,则可能导致子表数据连带被修复,这可能会修复一个不一致而引入另一个不一致;如果表上有触发器,也可能遇到同样问题。所以在有触发器和主外键约束的情况下要慎用。pt-table-sync工具同样也不欢迎主从异构的结构。pt-table-sync工具默认会进行先决条件的检查。

4.pt-table-sync在修复过程中不能容忍从库延迟,这正好与pt-table-checksum相反。如果从库延迟太多,pt-table-sync会长期持有对chunk的for update锁,然后等待从库的master_pos_wait执行完毕或超时。从库延迟越大,等待过程就越长,主库加锁的时间就越长,对线上影响就越大。因此要严格设置max-lag。

5.对从库数据的修复通常是在主库执行sql来同步到从库。因此,在有多个从库时,修复某个从库的数据实际会把修复语句同步到所有从库。数据修复的代价取决于从库与主库不一致的程度,如果某从库数据与主库非常不一致,举例说,这个从库只有表结构,那么需要把主库的所有数据重新灌一遍,然后通过binlog同步,同时会传递到所有从库。这会给线上带来很大压力,甚至拖垮集群。正确的做法是,先用pt-table-checksum校验一遍,确定不一致的程度:如果不同步的很少,用pt-table-sync直接修复;否则,用备份先替换它,然后用pt-table-sync修复。
说明: 这实际提供了一种对myisam备份的思路:如果仅有一个myisam的主库,要为其增加从库,则可以:先mysqldump出表结构到从库上,然后启动同步,然后用pt-table-sync来修复数据。

时间: 2024-07-31 06:20:22

使用pt-table-checksum及pt-table-sync校验复制一致性详细介绍的相关文章

Lua的table库函数insert、remove、concat、sort详细介绍

函数列表: table.insert(table,[ pos,] value) table.remove(table[, pos]) table.concat(table[, sep[, i[, j]]]) table.sort(table[, comp]) 1. insert 和 remove 只能用于数组元素的插入和移出, 进行插入和移出时,会将后面的元素对齐起来. 所以在 for 循环中进行 insert 和 remove 的时候要注意插入和移除时是否漏掉了某些项: local t = {

NXP ARM Vector Table CheckSum

Signature Creator for NXP Cortex-M Devices Algorithm for creating the checksum The reserved Cortex-M3 exception vector location 7 (offset 0x001C in the vector table) should contain the 2’s complement of the check-sum of table entries 0 through 6. Thi

Failed to load slave replication state from table mysql.gtid_slave_pos: 1146: Table &#39;mysql.gtid_slave_pos&#39; doesn&#39;t exist

http://anothermysqldba.blogspot.com/2013/06/mariadb-1003-alpha-install-on-fedora-17.html MariaDB 10.0.3 Alpha install on Fedora 17 x86_64 MariaDB 10.0.3 Alphawas just released. So for those of you that recall my previous MariaDB 5.5 install post, I d

bootstrap table 实现固定悬浮table 表头并可以水平滚动

在开发项目中,需要将表格头部固定,而且表格大多数情况下是会水平滚动的.项目的css框架是bootstrap 3,故也可以叫做bootstrap table. 需要实现的是:表格头部固定,并且支持水平滚动 html code(source table): <table id="top_fix_table" border="0" cellpadding="4" cellspacing="0" class="tabl

(原创) cocos2d-x 3.0+ lua 学习和工作(4) : 公共函数(5): 计算table元素个数:table.nums

这里的函数主要用来做:计算table元素个数.参考资料为quick_cocos. 星月倾心贡献~~~ 我们先看一段代码 local tbl = { [1] = 2, [2] = 2, [3] = 3 } print( "tbl length is " .. #tbl ) 这段代码是获得tbl的长度,即元素个数. 输出: tbl length is 3 拥有三个元素,没有问题.我们注意到元素的下标是,即key值是:1, 2, 3.即tbl[1], tbl[2], tbl[3].如果,我们

JQuery结合Ajax实现双击Table表格,使Table变成可编辑,并保存到数据库中

近期在做项目时,要实现通过双击Table表格的TR,使Table行变成可编辑,来实现修改数据并保存到数据库中的功能,无需多说,直接贴代码吧.希望能得到各位同仁指正. 1 function tdEdit(element, id) { 2 var i_a = "<input class='edit_td' type='text' style='height:30px; width:40px;' value='"; 3 var i_b = "'/>"; 4 v

create table as 和create table like的区别

create table as 和create table like的区别 对于MySQL的复制相同表结构方法,有create table as 和create table like 两种,区别是什么呢? /* -- 没有开启gtid的情况下,不拷贝数据,只创建一模一样的表结构,包括索引约束等,结合insert语句可以实现复制一个表的结构和数据的目的 create table tbl_test_bak like tbl_test; insert into tbl_test_bak select

How To Convert A Partitioned Table To A Non-Partitioned Table Using DataPump In 11g (Doc ID 1276049.1)

APPLIES TO: Oracle Database Exadata Cloud Machine - Version N/A and laterOracle Cloud Infrastructure - Database Service - Version N/A and laterOracle Database Cloud Exadata Service - Version N/A and laterOracle Database Exadata Express Cloud Service

MySQL SHOW TABLE 输出的每列详细介绍

Name: 表名 Engine: 表的存储引擎(旧版本中,该值为Type) Row_format: 行的格式.对于MyISAM表,可选的值为Dynamic.Fixed或者Copressed. Dynamic: 长度可变,一般包含可变长度的字段,如果VARCHAR或BLOB. Fixed: 长度固定,只包含固定长度的列, 如CHAR和INTEGER. Compressed: 只在压缩表中存在 Rows: 表中的行数.对于MyISAM和其它一些存储引擎,该值是精确的,但对于InnoDB该值是估算的.

truncate table语句和delete table语句的区别

truncate table 表名 ; delete from 表名; 都是用来删除表中所有的记录,前者删除数据后表的标识列会重新开始编号,它比delete语句使用的系统资源和事务日志资源更少,但是表的结构,列,约束,索引等不会被改动,同时不能用于有外键约束引用的表,在实际工作中,不建议使用truncate ,因为使用它删除的数据不能恢复还原,而使用delete的话就可以恢复