pt-table-checksum是校驗主從是否一致的校驗工具。sql
本文爲何使用的是DSN方式呢,由於喜歡自由,DSN方式能夠按照本身指定的方式發現從庫,而且查閱網上教程很難發現完整的DSN使用方式,致使我研究了很久,因此總結下本身的研究成果。數據庫
pt-table-checksum在基於binlog_format=row的模式下分別主庫和從庫上執行checksum的SQL語句,分別計算主庫和從庫表數據塊的checksum值。然後比較主從的checksum值是否一致來判斷主從數據是否一致。數據塊來自於根據主鍵/惟一索引將表的記錄(row)切分紅單個數據庫(chunck),同時也下降了數據庫的負載。安全
一、pt-table-checksum鏈接到主庫,並執行一系列變動參數語句,服務器
SET SESSION innodb_lock_wait_timeout=1; SET @@SQL_QUOTE_SHOW_CREATE = 1/*!40101, @@SQL_MODE='NO_AUTO_VALUE_ON_ZERO,NO_ENGINE_SUBSTITUTION'*/; SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO,NO_ENGINE_SUBSTITUTION'/*!50108 SET @@binlog_format := 'STATEMENT'*/; SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
二、從主庫上查找它的從庫,默認經過show full processlist方式,還能夠經過show slave hosts以及DSN方式發現從庫;session
三、查找從庫是否有複製過濾規則,能夠經過--nocheck-replication-filters跳過該項檢查;併發
四、檢查/建立checksums數據表,在確認數據表已經建立的前提下,能夠經過--[no]create-replication-table跳過該項檢查;socket
五、獲取一個個數據表,並依次檢查;函數
六、若是是表的第一個chunk,那麼chunk-size通常爲1000;若是不是表的第一個chunk,那麼採用19步中分析出的結果;工具
七、檢查表結構,進行數據類型轉換等,生成checksum的sql語句;測試
八、根據表上的索引和數據的分佈,選擇最合適的split表的方法;
九、開始對錶作checksum操做;
十、刪除該表的上一次checksum值,除非使用--resume參數;
十一、進入須要作checksum的數據庫中,USE database;
十二、獲取下一個chunk的數據記錄;
1三、explain該chunk的checksum語句;
1四、根據explain的結果判斷該chunk的大小是否超過自定義的--chunk-size的大小,若是超過,將會忽略計算出來的chunk-size,使用自定義的--chunk-size;
EXPLAIN SELECT COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `id`, CONCAT(ISNULL(`id`)))) AS UNSIGNED)), 10, 16)), 0) AS crc FROM `xxxx`.`xxxx` /*explain checksum table*/
1五、執行該chunk的checksum語句,該過程當中會把該chunk上的記錄加上for update鎖;
REPLACE INTO `percona`.`checksums` (db, tbl, chunk, chunk_index, lower_boundary, upper_boundary, this_cnt, this_crc) SELECT 'wing', 't', '1', NULL, NULL, NULL, COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `id`, CONCAT(ISNULL(`id`)))) AS UNSIGNED)), 10, 16)), 0) AS crc FROM `xxxx`.`xxxx` /*checksum table*/
1六、show warnings查看是否有警告信息等;
1七、獲取chunk的checksum值
SELECT this_crc, this_cnt FROM `percona`.`checksums` WHERE db = 'xxx' AND tbl = 'xxx' AND chunk = '1'
1八、更新主庫chunk的checksum值
UPDATE `percona`.`checksums` SET chunk_time = 'xxx', master_crc = 'xxxx', master_cnt = 'xxx' WHERE db = 'xxx' AND tbl = 'xxx' AND chunk = '1'
1九、調整下一個chunk的大小;
20、等待從庫追上主庫,此時若是主從延遲時間超過--max-load的設置值,pt工具將會暫停本身;
2一、若是發現主庫的max-load超過某個閾值,pt工具在這裏將暫停;
2二、繼續下一個chunk,直到這個table被chunk完畢;
2三、等待從庫執行完checksum,便於生成彙總的統計結果;
2四、發現並輸出該表的主從是否存在差別;
2五、循環每張表,直到全部表被檢查完畢;
2六、若是有warn/err/diff,則退出代碼爲1,正常退出爲0。
# 本示例爲DSN方式檢查 # 主庫上建立percona數據庫 CREATE DATABASE percona; # 主庫上建立checksums和dsns表 CREATE TABLE 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 DEFAULT CHARSET=utf8; CREATE TABLE `dsns` ( `id` int(11) NOT NULL AUTO_INCREMENT, `parent_id` int(11) DEFAULT NULL, `dsn` varchar(255) NOT NULL, PRIMARY KEY (`id`) ); # 主庫上建立一個用戶,從pt測試的服務器上既能夠經過該用戶鏈接主庫,也能夠經過該用戶鏈接從庫 GRANT ALL PRIVILEGEES on percona.* to 'percona_user'@'%' IDENTIFIED BY 'percona_pass'; GRANT SELECT,LOCK TABLES,PROCESS,SUPER on *.* to 'percona_user'@'%'; # 主庫上dsns表插入從庫信息 INSERT INTO dsns(dsn) VALUES('h=repl_host,P=repl_port') # 鏈接主庫執行pt工具 pt-table-checksum h='master_host',u='percona_user',p='percona_pass',P=master_port --databases=xxx --tables=xx,xxx --nocheck-replication-filters --nocreate-replicate-table --no-check-binlog-format --recursion-method dsn=h=repl_host,P=repl_port,D='percona',t='dsns' # 返回結果 TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE 03-08T20:31:22 0 1 xx xx 0 1.058 xxx.xx 03-08T20:32:22 0 0 xx xx 0 1.058 xxx.xxx
# pt-table-checksum工具檢測返回結果 TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE 03-08T20:31:22 0 1 xx xx 0 1.058 xxx.xx 03-08T20:32:22 0 0 xx xx 0 1.058 xxx.xxx
TS:pt工具結束執行的時間;
ERRORS:checksum表的時候出現的error和warn的次數;
DIFFS:當爲0時,該表主從不存在差別,當爲1時,該表主從存在差別;
ROWS:進行checksum的表的記錄數;
CHUNKS:表被split爲N個chunk,N爲chunk的數量;
SKIPPED:因爲如下緣由,pt跳過的chunk數;
>* MySQL not using the --chunk-index >* MySQL not using the full chunk index (--[no]check-plan) >* Chunk size is greater than --chunk-size * --chunk-size-limit >* Lock wait timeout exceeded (--retries) >* Checksum query killed (--retries) >
TIME:checksum表的時間長度;
TABLE:checksum相應的表名。
那麼如何經過checksums表發現差別呢,在每個從庫上執行以下SQL,便可選出有差別的表:
SELECT db, tbl, SUM(this_cnt) AS total_rows, COUNT(*) AS chunks FROM percona.checksums WHERE ( master_cnt <> this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <> ISNULL(this_crc)) GROUP BY db, tbl;
–nocheck-binlog-format
不檢查全部數據庫的binlog_format是否一致,請在確認全部數據庫的binlog_format一致的狀況下,使用該參數。
–chunk-index=s
使用該索引將表split到多個chunk中。
–chunk-size=z
指定chunk的大小,默認爲1000,即一個chunk容納1000條數據記錄。
–chunk-time=f
動態調整–chunk-size,當一個chunk的checksum時間超過該–chunk-time的時間。
–nocreate-replicate-table
不建立--replicate指定的database和table。
–function=s
指定checksum的hash函數,選擇項:FNV1A_64,MURMUR_HASH, SHA1, MD5, CRC32等。
–recursion-method=a
指定發現slave的方式,選擇項:
–replicate=s
將checksum的指定結果寫入到該表中,默認爲percona.checksums。
–resume
從上一次中斷的已完成的chunk開始繼續執行下一個chunk,最終完成整個表的checksum。
–where=s
僅僅校驗該where條件匹配的行數。
–ask-pass
交互式輸入數據庫驗證碼,命令行推薦使用。
–host
數據庫host。
–port
數據庫port。
–password
數據庫密碼。
–user
數據庫用戶。
–socket
數據庫的socket文件。
–columns=a
僅僅校驗指定的列。
–databases=h
僅僅校驗指定的數據庫。
–databases-regex=s
僅僅校驗與該參數匹配的數據庫。
–engines=h
僅僅校驗指定engine的表。
–tables=h
僅僅校驗指定的表。
–tables-regex=s
僅僅校驗與該參數匹配的表。