利用pt-table-checksum校驗數據一致性


相信很多人的線上都搭建了MySQL主從這樣的框架,很多人只監控MySQL的從服務器Slave_IO和Slave_SQL這兩個線程是否為YES,還有 Seconds_Behind_Master延遲大不大之類的一些信息。但他們是否定期的去檢查MySQL主服務器的數據和從服務器的數據是否一致呢,數據一致性才是最重要的,有人很好奇的問,如果數據不一致,就肯定沒有兩個YES的出現啦,我想說,不一定的,因為當slave出現錯誤時,可以通過SET GLOBAL sql_slave_skip_counter = N來跳過錯誤,還有可以通過選項--slave-skip-errors=[error_code]來跳過錯誤代碼,這樣處理后Slave_IO和Slave_SQL狀態依然為YES,但這個時候,數據可能就跟主庫不一致了。下面和大家學習一個很不錯的工具pt-table-checksum

pt-table-checksum:MySQL復制完整性校驗(這個工具的重點是找到有效數據的差異。如果任何數據是不同的,你可以用pt-table-sync解決問題。)

軟件包下載地址:http://www.percona.com/downloads/percona-toolkit/2.2.7/RPM/percona-toolkit-2.2.7-1.noarch.rpm

PT工具的安裝,可以參考我的博客:http://www.cnblogs.com/xuanzhi201111/p/4128894.html(主庫和從庫都要安裝)

 

實驗環境:   master(192.168.1.128:3306)

                slave(192.168.1.129:3306)

 

注意事項:

1、  根據測試,需要一個即能登錄主庫,也能登錄從庫的賬號;

2、  只能指定一個host,必須為主庫的IP;

3、  在檢查時會向表加S鎖;

4、  如果master和slave的binlog日志不是STATEMENT格式,要用--no-check-binlog-format選項

5、  運行之前需要從庫的同步IO和SQL進程是YES狀態。

6、  表要有主鍵索引或唯一鍵索引

 

在主庫上(master:3306),如下:

mysql> select * from check_sum.test1;  
+------+-------+
| id   | couse |
+------+-------+
|    1 | aa    |
|    2 | bb    |
|    3 | cc    |
+------+-------+
3 rows in set (0.00 sec)

mysql> 

在從庫(slave:3306),如下(跟master數據不一致了):

mysql> select * from check_sum.test1;
+------+-------+
| id   | couse |
+------+-------+
|    1 | aa    |
|    2 | bb    |
+------+-------+
2 rows in set (0.00 sec)

mysql> 

 

pt-table-checksum參數解釋:

--nocheck-replication-filters :不檢查復制過濾器,建議啟用。后面可以用--databases來指定需要檢查的數據庫。
--no-check-binlog-format      : 不檢查復制的binlog模式,要是binlog模式是ROW,則會報錯。
--replicate-check-only :只顯示不同步的信息。
--replicate=    :把checksum的信息寫入到指定表中,建議直接寫到被檢查的數據庫當中。 
--databases=    :指定需要被檢查的數據庫,多個則用逗號隔開。
--tables=       :指定需要被檢查的表,多個用逗號隔開
h=192.168.1.128 :Master的地址
u=root          :用戶名
p=123456        :密碼
P=3306          :端口


在主庫上執行數據檢查命令:

[root ~]$ pt-table-checksum  --nocheck-replication-filters --replicate=test.checksums --databases=check_sum  h=192.168.1.128,u=admin,p=123456,P=3306
Replica slave has binlog_format MIXED which could cause pt-table-checksum to break replication.  Please read "Replicas using row-based replication" in the LIMITATIONS section of the tool's documentation.  If you 
understand the risks, specify --no-check-binlog-format to disable this check.

上面報錯了,意思說如果binlog_format 為MIXED格式,會破壞同步,可以使用--no-check-binlog-format選項來關閉檢查

 

添加上--no-check-binlog-format選項,再在master庫上執行,報以下錯(標紅的為報錯信息):

[root ~]$ pt-table-checksum  --nocheck-replication-filters --no-check-binlog-format  --replicate=test.checksums --databases=check_sum  h=192.168.1.128,u=admin,p=123456,P=3306
Cannot connect to P=3306,h=192.168.1.129,p=...,u=root Diffs cannot be detected because no slaves were found.  Please read the --recursion-method documentation for information.
            TS ERRORS  DIFFS     ROWS  CHUNKS SKIPPED    TIME TABLE
04-13T15:44:23      0      0        3       1       0   0.044 check_sum.test1

上面已經告訴你怎么做了, Please read the --recursion-method documentation for information,上面的提示信息很清楚,因為找不到slave庫,所以執行失敗。用參數--recursion-method 可以指定模式解決,關於--recursion-method參數的設置有:

METHOD       USES
===========  =============================================
processlist  SHOW PROCESSLIST
hosts        SHOW SLAVE HOSTS
cluster      SHOW STATUS LIKE 'wsrep\_incoming\_addresses'
dsn=DSN      DSNs from a table
none         Do not find slaves

默認是通過show processlist 找到host的值或show slave hosts 找到host的值

*************************** 1. row ***************************
     Id: 7
   User: admin
   Host: 192.168.1.129:60195
     db: NULL
Command: Binlog Dump
   Time: 663201
  State: Master has sent all binlog to slave; waiting for binlog to be updated
   Info: NULL
*************************** 2. row ***************************
     Id: 37
   User: root
   Host: localhost
     db: check_sum
Command: Query
   Time: 0
  State: NULL
   Info: show processlist
4 rows in set (0.00 sec)

還有一種方法是show slave hosts;前提從庫配置文件里面已經配置自己的地址和端口,在slave庫上操作(在[mysqld]下添加這兩行):

[root mysql-5.5.40]$ cat  my.cnf |grep "report"
report_host=192.168.1.129
report_port=3306

回到master庫操作:

mysql> show slave hosts;
+-----------+---------------+------+-----------+
| Server_id | Host          | Port | Master_id |
+-----------+---------------+------+-----------+
|        11 | 192.168.1.129 | 3306 |         1 |
+-----------+---------------+------+-----------+
1 row in set (0.00 sec)

mysql> 

最重要的一點是我們需要在從庫上授權,能讓主庫訪問,只能指定一個host,必須為主庫的IP,在slave庫上操作;

mysql>GRANT SELECT, PROCESS, SUPER, REPLICATION SLAVE ON *.* TO 'admin'@'192.168.1.128' IDENTIFIED BY '123456';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql>

如果在master沒有讓admin用戶登錄的權利,要在master庫給admin權限,很多人用root用戶來檢查,所以只要在從庫權限即可(在master庫上操作):

mysql>GRANT SELECT, PROCESS, SUPER, REPLICATION SLAVE ON *.* TO 'admin'@'192.168.1.128' IDENTIFIED BY '123456';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> 

權限解釋:

select     //查看所有庫的表,原理可加 explain選項查看
process    //show processlist
super      //set binlog_format='statement'
replication slave   //show slave hosts

 

現在我們再來檢測數據一致性(master庫上操作):

[root ~]$ pt-table-checksum  --nocheck-replication-filters --no-check-binlog-format --replicate=test.checksums --databases=check_sum  h=192.168.1.128,u=admin,p=123456,P=3306  
            TS ERRORS  DIFFS     ROWS  CHUNKS SKIPPED    TIME TABLE
12-26T15:38:30      0      1        3       1       0   0.339 check_sum.test1

看到已經檢查出主從數據有不一致了,DIFFS下的值為1,怎么不一致呢? 通過指定--replicate=test.checksums 參數,就說明把檢查信息都寫到了checksums表中

下面對例的含義進行解釋:

TS            :完成檢查的時間。
ERRORS        :檢查時候發生錯誤和警告的數量。
DIFFS         :0表示一致,1表示不一致。當指定--no-replicate-check時,會一直為0,當指定--replicate-check-only會顯示不同的信息。
ROWS          :表的行數。
CHUNKS        :被划分到表中的塊的數目。
SKIPPED       :由於錯誤或警告或過大,則跳過塊的數目。
TIME          :執行的時間。
TABLE         :被檢查的表名。


之前一直以為去master的test.checksums表查看主庫與從庫不一致的信息,糾結了N久,前面顯示了DIFFS下的值為1,但master上看表里的信息如下:

mysql> select * from test.checksums\G
*************************** 1. row ***************************
            db: check_sum
           tbl: test1
         chunk: 1
    chunk_time: 0.023619
   chunk_index: NULL
lower_boundary: NULL
upper_boundary: NULL
      this_crc: d5b7731c   #slave
      this_cnt: 3               #slave
    master_crc: d5b7731c  #master
    master_cnt: 3              #master             ts: 2014-12-26 15:50:29
1 row in set (0.00 sec)

mysql> 

看到了吧,它們信息一樣,正常來說,表里信息應該是master跟slave不一致才對的,現在是一致,如果test.checksum里的對比是一樣的,是不能把slave庫少了的數據從master庫同步過去的,因為pt-table-sync同步數據時,要借助test.checksum表。別急:我們再去看一下slave庫下的test.checksums:(slave庫操作)

mysql> select * from test.checksums\G
*************************** 1. row ***************************
            db: check_sum
           tbl: test1
         chunk: 1
    chunk_time: 0.023619
   chunk_index: NULL
lower_boundary: NULL
upper_boundary: NULL
      this_crc: 64fdcfa3
      this_cnt: 2 #slave 2行數據    
    master_crc: d5b7731c
    master_cnt: 3 #master 3行數據
            ts: 2014-12-26 15:50:29
1 row in set (0.00 sec)

在master庫可以可以用--print選項打印出master下的check_sum.test1和slave庫的check_sum.test1的不一致的數據,如下:

[root ~]$  pt-table-sync --replicate=test.checksums h=192.168.1.128,u=admin,p=123456,P=3306 h=192.168.1.129,u=admin,p=123456,P=3306 --print
Can't make changes on the master because no unique index exists at /usr/bin/pt-table-sync line 10648.  while doing check_sum.test1 on 192.168.1.129

以上報錯了,報錯信息也很明顯,說表沒有唯一索引,在master庫上給表添加主鍵索引或者唯一索引:

mysql> alter table test1 add primary key (id);
Query OK, 3 rows affected (0.17 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> show create table test1\G
*************************** 1. row ***************************
       Table: test1
Create Table: CREATE TABLE `test1` (
  `id` int(11) NOT NULL DEFAULT '0',
  `couse` char(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> 

再在master執行一次pt-table-checksum,再執行pt-table-sync,如下:

[root ~]$ pt-table-checksum  --nocheck-replication-filters --no-check-binlog-format --replicate=test.checksums --databases=check_sum  h=192.168.1.128,u=admin,p=123456,P=3306
            TS ERRORS  DIFFS     ROWS  CHUNKS SKIPPED    TIME TABLE
12-26T17:16:50      0      1        3       1       0   0.151 check_sum.test1

[root ~]$ pt-table-sync --replicate=test.checksums h=192.168.1.128,u=admin,p=123456,P=3306 h=192.168.1.129,u=admin,p=123456,P=3306 --print REPLACE INTO `check_sum`.`test1`(`id`, `couse`) VALUES ('3', 'cc') /*percona-toolkit src_db:check_sum src_tbl:test1 src_dsn:P=3306,h=192.168.1.128,p=...,u=admin dst_db:check_sum dst_tbl:test1 dst_dsn:P=3306, h=192.168.1.129,p=...,u=admin lock:1 transaction:1 changing_src:test.checksums replicate:test.checksums bidirectional:0 pid:41368 user:root host:localhost.localdomain*/;

大家都看到了有不一致的數據記錄了吧

 

參數說明:

--replicate=    :指定通過pt-table-checksum得到的表.
--databases=    : 指定執行同步的數據庫,多個用逗號隔開。
--tables=       :指定執行同步的表,多個用逗號隔開。
--sync-to-master :指定一個DSN,即從的IP,他會通過show processlist或show slave status 去自動的找主。
h=127.0.0.1     :服務器地址,命令里有2個ip,第一次出現的是Master的地址,第2次是Slave的地址。
u=root          :帳號。
p=123456        :密碼。
--print         :打印,但不執行命令。
--execute       :執行命令。

接下的操作就是把slave上少的數據,從master同步過去(master操作):

通過(--execute),讓它們數據保持一致性:

[root ~]$ pt-table-sync --replicate=test.checksums h=192.168.1.128,u=admin,p=123456,P=3306 h=192.168.1.129,u=admin,p=123456,P=3306 --execute   
INSERT,DELETE command denied to user 'admin'@'192.168.1.128' for table 'test1' [for Statement "REPLACE INTO `check_sum`.`test1`(`id`, `couse`) VALUES ('3', 'cc') 
/*percona-toolkit src_db:check_sum src_tbl:test1 src_dsn:P=3306,h=192.168.1.128,p=...,u=admin dst_db:check_sum dst_tbl:test1 dst_dsn:P=3306,h=192.168.1.129,p=...,u=admin lock:1 transaction:1 
changing_src:test.checksums replicate:test.checksums bidirectional:0 pid:41650 user:root host:localhost.localdomain*/"] at line 10707 while doing check_sum.test1 on 192.168.1.129

看到報錯了吧,提示admin用戶沒有INSERT、DELETE權限(如果是root用戶,就沒這些小問題),在master授權admin用戶權限后再執行如下命令(master操作):

[root ~]$ pt-table-sync --replicate=test.checksums h=192.168.1.128,u=admin,p=123456,P=3306 h=192.168.1.129,u=admin,p=123456,P=3306 --execute
 
[root ~]$ pt-table-checksum  --nocheck-replication-filters --no-check-binlog-format --replicate=test.checksums --databases=check_sum  h=192.168.1.128,u=admin,p=123456,P=3306 
            TS ERRORS  DIFFS     ROWS  CHUNKS SKIPPED    TIME TABLE
12-26T17:57:18      0      0        3       1       0   0.073 check_sum.test1

可以看到再次檢查的時候,DIFFS已經是0了,去slave查看一下表的數據(slave操作):

mysql> select * from check_sum.test1;
+----+-------+
| id | couse |
+----+-------+
|  1 | aa    |
|  2 | bb    |
|  3 | cc    |
+----+-------+
3 rows in set (0.00 sec)

已經跟master上的數據一致了。

 

 

第二種情況:(slave的端口不是3306,則要用另一種方式去檢查)

環境:192.168.1.128:3306(master)

         192.168.1.129:3307(slave)

執行數據檢查命令pt-table-checksum:

[root ~]$  pt-table-checksum  --nocheck-replication-filters --no-check-binlog-format --replicate=test.checksums --databases=check_sum  h=192.168.1.128,u=admin,p=123456,P=3306       
Cannot connect to P=3306,h=192.168.1.129,p=...,u=admin Diffs cannot be detected because no slaves were found.  Please read the --recursion-method documentation for information.
            TS ERRORS  DIFFS     ROWS  CHUNKS SKIPPED    TIME TABLE
12-26T19:59:11      0      0        3       1       0   0.065 check_sum.test1

以上報錯了,因為pt-table-checksum默認是找slave庫的3306,現在slave上的端口是3307了(在master操作):

mysql> show slave hosts;
+-----------+---------------+------+-----------+
| Server_id | Host          | Port | Master_id |
+-----------+---------------+------+-----------+
|        11 | 192.168.1.129 | 3307 |         1 |
+-----------+---------------+------+-----------+
1 row in set (0.00 sec)

mysql> 

在master上test庫上創建一個表:

mysql> use test
Database changed
mysql> CREATE TABLE `dsns` ( `id` int(11) NOT NULL AUTO_INCREMENT, `parent_id` int(11) DEFAULT NULL, `dsn` varchar(255) NOT NULL, PRIMARY KEY (`id`) );
Query OK, 0 rows affected (0.08 sec)
mysql> 

寫入從庫信息,如果有多個從庫,就插入多條記錄:

mysql> INSERT INTO dsns (parent_id,dsn) values(1, "h=192.168.1.129,u=admin,p=123456,P=3307");                               
Query OK, 1 row affected (0.04 sec)

mysql> select * from dsns;
+----+-----------+-----------------------------------------+
| id | parent_id | dsn                                     |
+----+-----------+-----------------------------------------+
|  1 |         1 | h=192.168.1.129,u=admin,p=123456,P=3307 |
+----+-----------+-----------------------------------------+
1 row in set (0.00 sec)


然后在master上執行數據校驗命令:

[root ~]$  pt-table-checksum  --nocheck-replication-filters --no-check-binlog-format --replicate=test.checksums --databases=check_sum  h=192.168.1.128,u=admin,p=123456,P=3306--recursion-method=dsn=h=192.168.1.128,
D=test,t=dsns
TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE 12-26T20:10:30 0 0 3 1 0 0.100 check_sum.test1

在slave庫執行刪除數據操作:

mysql> select * from test1;
+----+-------+
| id | couse |
+----+-------+
|  1 | aa    |
|  2 | bb    |
|  3 | cc    |
+----+-------+
3 rows in set (0.00 sec)

mysql> delete from test1 where id=3;
Query OK, 1 row affected (0.00 sec)

再在master庫執行數據校驗命令:

[root ~]$  pt-table-checksum  --nocheck-replication-filters --no-check-binlog-format --replicate=test.checksums --databases=check_sum  h=192.168.1.128,u=admin,p=123456,P=3306 --recursion-method=dsn=h=192.168.1.128,
D=test,t=dsns
            TS ERRORS  DIFFS     ROWS  CHUNKS SKIPPED    TIME TABLE
12-26T20:25:42      0      1        3       1       0   0.020 check_sum.test1

已經檢查出數據不一致了,至於怎么把數據同步到從庫,還沒研究出來,按第一種方法,再換一下端口,也不行,因為pt-table-sync默認找3306端口,如果你研究出來了,分享下哈,哈哈^.^

 

 總結pt-table-checksum和pt-table-sync工具是非常好用的數據檢查及修復的工具,在日常生活中會經常用到,可以寫腳本去監控數據的一致性

 

參考資料:http://www.percona.com/doc/percona-toolkit/2.2/pt-table-checksum.html

              http://www.percona.com/doc/percona-toolkit/2.2/pt-table-sync.html

              http://keithlan.github.io/2016/05/25/pt_table_checksum/

作者:陸炫志

出處:xuanzhi的博客 http://www.cnblogs.com/xuanzhi201111

您的支持是對博主最大的鼓勵,感謝您的認真閱讀。本文版權歸作者所有,歡迎轉載,但請保留該聲明。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM