使用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-MySQL

 

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 數據庫創建用戶及授權。如果用戶權限夠大的話,不用提前創建percona數據庫和checksums表,會自動創建的。

CREATE DATABASE IF NOT EXISTS percona ;


CREATE TABLE IF NOT EXISTS percona.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;

 

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

 

5.校驗(Master服務器運行)

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

 

pt-table-checksum --nocheck-binlog-format --nocheck-plan --nocheck-replication-filters  --set-vars innodb_lock_wait_timeout=120 --recursion-method=processlist --databases=data_etl  -u'root' -p'nihao' -h10.0.20.38    (推薦)

pt-table-checksum --nocheck-binlog-format --nocheck-plan --nocheck-replication-filters --replicate=pt.checksums --set-vars innodb_lock_wait_timeout=120 --recursion-method=processlist --databases=data_etl  -u'root' --ask-pass -h10.0.20.38

 

這里糾正一個認識,網上很多人說 pt-table-checksum 要在主庫上執行,其實不是的,我的mysql實例比較多,只需在某一台服務器上安裝percona-toolkit,這台服務能夠同時訪問主庫和從庫就行了,只需修改 -h 指定的ip即可

常用參數:

--nocheck-replication-filters :不檢查復制過濾器,檢測中忽略mysql配置參數binlog_ignore_db等,建議啟用后面可以用--databases來指定需要檢查的數據庫--no-check-binlog-format      : 不檢查復制的binlog模式,因為該工具只檢查主從日志格式binlog模式必須是Statement,如果是ROW則會報錯,此時則需要添加該參數。
--replicate-check-only        :只顯示不同步的信息。
--replicate=   :把checksum的信息寫入到指定的庫中的表中,如果不使用該選項則會默認自動創建 percona.checksums 表,默認存儲到percona庫的checksums中。
--databases=   :指定需要被檢查的數據庫,多個則用逗號隔開
--tables=      :指定需要被檢查的表,   多個則用逗號隔開
--host=127.0.0.1 或-h127.0.0.1 或 h=127.0.0.1   :Master的地址
--user=root       或-uroot      或 u=root        :用戶名
--password=123456 或-p123456    或 p=123456      :密碼,如有特殊字符時需要使用引號
--port=3306       或-P3306 或 P=3306 :端口
--socket= :指定socket接口路徑
值得注意的是采用最右邊格式時,中間需要加逗號隔開: h=127.0.0.1,u=root,p='123456',P=3306 ,左邊兩種則不用。
--recursion-method  : 在有些情況下,recursion-method如果不設會報錯:Diffs cannot be detected because no slaves were found. 
其參數有四:processlist/hosts/dsn=DSN/no,用來決定查找slave的方式是show full processlist還是show slave hosts還是命令行直接指定還是壓根就不准備找從庫
默認采用show full processlist來查找從庫,但是這只有在主從實例端口相同的情況下才有效
--ask-pass  不在命令行指定密碼,手動輸入
--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 ROWS CHUNKS SKIPPED TIME TABLE
05-08T16:21:06 0 1 4 1 0 0.012 rep_test.test1
TS            :完成檢查的時間。
ERRORS        :檢查時候發生錯誤和警告的數量。
DIFFS0表示一致,1表示不一致。當指定--no-replicate-check時,會一直為0,當指定--replicate-check-only會顯示不同的信息。
ROWS          :表的行數。
CHUNKS        :被划分到表中的塊的數目。
SKIPPED       :由於錯誤或警告或過大,則跳過塊的數目。
TIME          :執行的時間。
TABLE         :被檢查的表名。

備注:主要觀察DIFFS列,標識差異數。

pt-table-checksum運行在主庫上,通過show processlist或show slave hosts或DSN方式來確定從庫並連接,默認使用crc32算法來進行數據校驗,該工具之所以需要把binlog設置為statement格式,是因為該工具能得出主從是否一致所依賴的就是statement基礎上同樣的SQL語句在主從庫上各自的執行結果,主庫進行檢查后sql語句傳給從庫,從庫執行一遍后,也得到自己的結果。 

 

 

6.查看差異(Slave庫運行)

執行pt-table-checksum校驗結束后,在每個從庫上,執行如下的sql語句即可看到是否有主從不一致發生:

mysql> 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;

+------+-----------+------------+--------+
| db     | tbl            | total_rows  | chunks |
+------+-----------+------------+--------+
| apps | msg_log_6 | 1               | 1 |
+------+-----------+------------+--------+

mysql> select * from percona.checksums where master_cnt <> this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <> ISNULL(this_crc) \G

*************************** 1. row ***************************

                     db: apps
                     tbl: msg_log_6
                chunk: 1
        chunk_time: 0.15145
      chunk_index: NULL
 lower_boundary: NULL
upper_boundary: NULL
            this_crc: e663eb4c
            this_cnt: 1
        master_crc: e663eb44
        master_cnt: 1
                     ts: 2016-05-05 16:46:34
1 row in set (0.00 sec)

如果數據一致沒問題的話,會無任何輸出,只會顯示不一致的某個表的相關信息。

 

7.復制,消除差異 ---- (主或從上執行都可)

假設newtables數據庫tb1表存在差異

  • 自動消除差異(不推薦)

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

 

  • 打印出消除差異需要執行的sql語句,人工干預到Slave庫執行(推薦

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

或者

pt-table-sync --print --sync-to-master h=10.0.0.7,P=3306,u=checksums,p='checksums' --replicate percona.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來修復數據。

 

注意:要是表中沒有唯一索引或則主鍵則會報錯:

Can't make changes on the master because no unique index exists at /usr/local/bin/pt-table-sync line 10591.

 

 

參考資料:

https://segmentfault.com/a/1190000004309169

http://www.cnblogs.com/xiaoyanger/p/5584554.html

 


免責聲明!

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



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