pt-table-checksum-MySQL主從校驗工具使用(DSN方式)

pt-table-checksum是校驗主從是否一致的校驗工具。sql

本文爲何使用的是DSN方式呢,由於喜歡自由,DSN方式能夠按照本身指定的方式發現從庫,而且查閱網上教程很難發現完整的DSN使用方式,致使我研究了很久,因此總結下本身的研究成果。數據庫

1、原理

pt-table-checksum在基於binlog_format=row的模式下分別主庫和從庫上執行checksum的SQL語句,分別計算主庫和從庫表數據塊的checksum值。然後比較主從的checksum值是否一致來判斷主從數據是否一致。數據塊來自於根據主鍵/惟一索引將表的記錄(row)切分紅單個數據庫(chunck),同時也下降了數據庫的負載。安全

2、安全性

  • pt-table-checksum一次檢查一個表,而且將每一個表的數據切分紅多個單個的數據塊,從而下降數據庫的壓力,而且在pt-table-checksum的執行過程當中,它會自動檢測數據庫的負載、主從複製延遲,若是負載過大或者主從延遲過大,此時pt-table-checksum會自動暫停,進而下降數據庫的負載或者主從複製延遲;
  • pt-table-checksum自動設置session級別的innodb_lock_wait_timeout爲1s,避免影響業務SQL的lock wait timeout;
  • pt-table-checksum使用--max-load參數控制數據庫負載,當數據庫負載超過設置的閥值時,pt-table-checksum將會暫停本身,下降數據庫壓力。默認狀況下,--max-load的主從複製延遲閥值爲1s,併發線程(Threads_running)爲25;
  • 當用 Ctrl+C 中止任務後,工具會正常的完成當前 chunk 檢測,下次使用--resume選項啓動能夠恢復繼續下一個 chunk。

3、工做原理

一、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。

4、使用示例

# 本示例爲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

5、結果解析

#  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相應的表名。

6、發現差別

那麼如何經過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;

7、經常使用參數

–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

僅僅校驗與該參數匹配的表。

相關文章
相關標籤/搜索