1. 程式人生 > >Percona Toolkit使用之pt-table-checksum

Percona Toolkit使用之pt-table-checksum

     pt-table-checksum的功能是校驗MySQL複製完整性。

     用法如下:

pt-table-checksum [OPTIONS] [DSN]

     pt-table-checksum通過在master上執行checksum查詢來實施線上複製一致性檢查,如果在replica上產生不同的checksum結果,replica就和master資料不一致。可選項DSN(MySQL連線訪問)指定master伺服器。如果發現不一致、或者產生警告和報錯,該工具的退出狀態為非0。

     以下命令會連線到localhost上的複製master,校驗每張表,然後報告每一個檢測到的replica的校驗結果:

pt-table-checksum

     pt-table-checksum設計用於在幾乎所有的情況下預設做正確的事情。存在疑問時,使用--explain選項檢視該工具如何校驗表。以下是該工具如何作用的高層次概觀。

     較於舊版本的pt-table-checksum,現在該工具專注於單個目的,不再有大量複雜性和對多種不同校驗技術的支援。它只在一臺伺服器上執行校驗查詢,然後校驗查詢通過複製流入到replica再執行。如果你需要舊版特性,可以使用Percona Toolkit version 1.0。

     pt-table-checksum連線到你指定的伺服器,查詢匹配你指定篩選的庫表(如果指定了的話)。它一次作用於一張表,所以不會佔用大量記憶體,開始校驗前也不會做很多工作。這使它在非常大的伺服器上可用。我們已經將它使用到有成百上千庫表、萬億行記錄的伺服器。無論多大的伺服器,pt-table-checksum執行得同樣好。

     它可以在非常大的表上工作的一個原因是它將每張表的記錄分割成塊,然後用單個“ REPLACE …SELECT ”查詢來計算每個記錄塊的checksum。它會改變塊大小來使checksum查詢在設想大小的時間內執行。將表分塊而不是對每個表進行單個大查詢的目的就是確保checksum查詢是非入侵式的,不會導致伺服器過大的複製延遲和負載。這就是為什麼每個塊的目標時間預設是0.5秒的原因。

     該工具對伺服器能夠多快地執行校驗查詢進行追蹤,然後當它瞭解到更多有關伺服器的效能後,對塊大小進行調整。它使用指數衰減加權平均來保持塊大小穩定,但是出於任何原因,如果在checksum查詢時伺服器的效能改變,它會保持響應。這意味著該工具可以快速自我調節,例如如果你的伺服器在流量高峰或者後臺任務而變得高負載時。

     分塊是通過一種在Percona Toolkit其他工具中曾被稱為“ nibbling ”的技術實現的。例如它和用於pt-archiver(https://www.percona.com/doc/percona-toolkit/LATEST/pt-archiver.html)的是相同的技術。在舊版本pt-table-checksum中遺留使用的分塊演算法被移除,因為它們不能生成預想大小的塊,而且在很多表上不能很好地工作。將表分割成塊的全部所需就是索引(最好是主鍵或者唯一索引)。如果沒有索引,而表含有適宜的小數目記錄,工具就會在單個塊裡面校驗該表。

     pt-table-checksum包含很多其他的防護措施來確保不影響伺服器的任何操作,包括replica。為了實現這一點,pt-table-checksum自動檢測和連線replica。(這如果失敗了,你可以使用--recursion-method選項給它一個提示)。

     該工具持續監視replica。如果有replica落後複製太遠,pt-table-checksum掛起以使其追趕上來。如果replica出錯或者複製停止,pt-table-checksum中斷然後等待。另外,pt-table-checksum會查詢問題產生的常見原因,例如複製篩選過濾,除非你強制它,否則它拒絕操作。複製篩選過濾是危險的,因為pt-table-checksum執行的查詢可能與其發生衝突而導致複製失敗。

     pt-table-checksum會驗證塊的大小不會太大,以安全地進行checksum。它對每個塊執行一個EXPLAIN查詢,然後忽略那些可能會大於期望行數的塊。你可以使用--chunk-size-limit選項來配置該防護措施的靈敏度。如果一張表因為包含的記錄量小而將被置於單個塊中checksum,pt-table-checksum會去額外驗證該表在replica上不會過大。這避免了以下情況:表在master上空的但在replica上非常大,然後在單個大查詢裡面checksum的話,就會導致一個非常長的複製延遲。

     還有一些其他的防護措施。例如,pt-table-checksum會設定其會話級別的innodb_lock_wait_timeout為1秒,以便如果出現鎖等待,它會成為犧牲者而不是導致其他查詢超時。另一個防護措施檢查資料庫伺服器上的負載,如果負載太高就會中斷。對於如何去做這一點並沒有一個正確的答案,預設情況下如果並行查詢超過25個pt-table-checksum就會掛起。你可以使用--max-load選項設定一個就你的伺服器而言的穩健值。

     checksum操作通常是讓步於伺服器上其他工作的低優先順序任務。然而,一個必須頻繁重啟的工具是很難使用的。於是,pt-table-checksum對錯誤有很強的適應能力。例如,如果資料庫管理員出於任何原因需要殺死pt-table-checksum的查詢,這不會是一個致命錯誤。使用者經常使用pt-kill(https://blog.csdn.net/sweeper_freedoman/article/details/79838375)來殺死長時間執行的checksum查詢。該工具會嘗試再執行一次被殺死的查詢,如果還執行失敗,它會轉移到該表的下一個塊。如果發生鎖等待超時,使用同樣的行為。如果出現該錯誤,工具會輸出一個警告,但每張表只打印一次。如果到伺服器的連線失敗,pt-table-checksum會嘗試去重新連線然後繼續工作。

     如果pt-table-checksum遇到使它完全停止的狀況,可以方便地使用--resume選項恢復。它會從它處理的最近一個表的最近一個塊開始。你也可以使用CRTL-C安全停止該工具。它將完成當前正在處理的塊然後退出。之後你仍然可以恢復它。

     當pt-table-checksum完成一張表中所有塊的checksum後,它會掛起,然後等待所有檢測到的replica執行完checksum查詢。查詢一旦執行結束,它會檢查所有的replica來看它們是否同master具有相同的資料,然後打印出一行包含結果的輸出。

     該工具在耗時操作時列印進度指示器。每個表checksum時它都會列印一個進度指示器。進度計算自表中記錄的預估值。當掛起以等待複製追趕上來以及進行replica與master不一致檢查等待時,它也會列印進度報告。你可以使用--quiet選項讓輸出不那麼冗長。

     如果你願意,你可以手動查詢checksum表來得到一份哪些表和塊與master不一致的報告。以下查詢會彙報每個有不一致的庫表,以及可能受影響的塊和記錄的數量的彙總資訊。該查詢中引用的表為checksum表,是checksum結果儲存的地方。該表中的每一行都包含伺服器裡某個表的一個塊的checksum資料。

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;

     需要考慮到pt-table-checksum預設使用CRC32進行checksum。CRC32不是一個密碼演算法因此它容易發生衝突。但是另一方面,CRC32演算法相較MD5和SHA1更快,也是非CPU密集型的。

     pt-table-checksum需要基於行的複製(statement-based replication),它在master上設定binlog_format=STATEMENT,但是由於MySQL的限制,replica並不遵循該修改。因此,checksum查詢不會複製到使用基於行的複製(row-based replication),是之後replica的master的replica(鏈式複製拓撲結構中扮演兩種角色的中間replica:既是之前master的replica,又是之後replica的master)。該工具自動檢查所有伺服器的binlog_format。參考--[no]check-binlog-format。

     該工具假定master和所有replica上的庫表是相同的。複製會失敗,例如,如果replica沒有master上存在的庫(並且該庫被執行了checksum),或者如果replica上表的結構與其在master上的不一致。

     該工具打印表格化結果,每張表一行。錯誤、警告以及進度報告會列印到標準誤。參考--quiet選項。當工具完成對錶的checksum,該表的結果就會被列印輸出。

            TS ERRORS  DIFFS  ROWS  CHUNKS SKIPPED    TIME TABLE
10-20T08:36:50      0      0   200       1       0   0.005 db1.tbl1
10-20T08:36:50      0      0   603       7       0   0.035 db1.tbl2
10-20T08:36:50      0      0    16       1       0   0.003 db2.tbl3
10-20T08:36:50      0      0   600       6       0   0.024 db2.tbl4
  • TS

工具完成對該表的checksum時的時間戳(不包含年份)。

  • ERRORS

對該表執行checksum時發生的錯誤和警告計數。當該表在執行時錯誤和警告也會列印到標準誤。

  • DIFFS

一個或多個replica上異於master的塊計數。如果指定--no-replicate-check選項,該列將一直為0。如果指定--replicate-check-only選項,只有出現不一致的表才會被列印輸出。

  • ROWS

表中被查詢和checksum的行數。它可能和你使用where選項得到的該表的行數不一致。

  • CHUNKS

該表被分割的塊數。

  • SKIPPED

由於這些問題中的一個或多個而跳過的塊數。自pt-table-checksum 2.2.5版本起,塊跳過將產生一個非0退出狀態。

  1. MySQL沒有使用--chunk-index
  2. MySQL沒有使用全部塊索引(--[no]check-plan)
  3. 塊大小大於--chunk-size * --chunk-size-limit
  4. 鎖等待超時(--retries)
  5. checksum查詢被殺死(--retries)
  • TABLE

被checksum的庫表。

如果指定--replicate-check-only選項,只有檢測到的replica上的checksum不一致才會被列印輸出。輸出是不一樣的:一個replica一段,一個checksum不一致一行,並且值以空格分割。

Differences on h=127.0.0.1,P=12346
TABLE CHUNK CNT_DIFF CRC_DIFF CHUNK_INDEX LOWER_BOUNDARY UPPER_BOUNDARY
db1.tbl1 1 0 1 PRIMARY 1 100
db1.tbl1 6 0 1 PRIMARY 501 600

Differences on h=127.0.0.1,P=12347
TABLE CHUNK CNT_DIFF CRC_DIFF CHUNK_INDEX LOWER_BOUNDARY UPPER_BOUNDARY
db1.tbl1 1 0 1 PRIMARY 1 100
db2.tbl2 9 5 0 PRIMARY 101 200

    ①TABLE

與master不一致的庫表。

     ②CHUNK

該表與master不一致的塊號。

     ③CNT_DIFF

replica上的塊行數減去master上的塊行數。

     ④CRC_DIFF

如果replica上該塊的CRC和master上該塊的CRC不一致則為1;否則為0。

     ⑤CHUNK_INDEX

對該表分塊時使用的索引。

     ⑥LOWER_BOUNDARY

定義該塊下界的索引值。

     ⑦UPPER_BOUNDARY

定義該塊上界的索引值。

     pt-table-checksum有三種可能的退出狀態:0、255、以及其他值是帶有不同問題標誌的位掩碼。0退出狀態指示沒有錯誤、警告、checksum不一致、跳過塊或表。255退出狀態指示致命錯誤。換句話說:該工具死了或者崩潰了。該錯誤會列印輸出到STDERR。如果退出狀態不是0或者255,則其值為帶有以下標誌的位掩碼。

FLAG              BIT VALUE  MEANING
================  =========  ==========================================
ERROR                     1  A non-fatal error occurred
ALREADY_RUNNING           2  --pid file exists and the PID is running
CAUGHT_SIGNAL             4  Caught SIGHUP, SIGINT, SIGPIPE, or SIGTERM
NO_SLAVES_FOUND           8  No replicas or cluster nodes were found
TABLE_DIFF               16  At least one diff was found
SKIP_CHUNK               32  At least one chunk was skipped
SKIP_TABLE               64  At least one table was skipped

     以下為個人本地環境的測試資料。由於MySQL配置的是基於GTID的新複製技術,pt-table-checksum採用當前最新版3.0.9,當前環境的問題是需要手動設定一下binlog_format才能checksum出master與slave之間的資料不一致。

     首先是master上不一致的表。

mysql> SELECT * FROM `player`.`player_def`;
+----+--------+-------+-------------+
| id | number | name  | role        |
+----+--------+-------+-------------+
|  1 |      1 | hachi | GK          |
|  2 |      2 | ni    | left back   |
|  3 |      3 | san   | center back |
|  4 |      4 | yon   | center back |
|  5 |      5 | go    | right back  |
+----+--------+-------+-------------+
5 rows in set (0.00 sec)

     然後是slave上同一張表的情況(其實是張清除了資料的空表)。

mysql> SELECT * FROM `player`.`player_def`;
Empty set (0.00 sec)

     執行pt-table-checksum檢查不一致性。

mysql> 
mysql> SHOW VARIABLES LIKE 'gtid_mode';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| gtid_mode     | ON    |
+---------------+-------+
1 row in set (0.01 sec)

mysql> SHOW VARIABLES LIKE 'binlog_format';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW   |
+---------------+-------+
1 row in set (0.01 sec)

mysql> SET GLOBAL binlog_format = 'STATEMENT';                                                                                         
Query OK, 0 rows affected (0.00 sec)

mysql> system pt-table-checksum -h192.168.112.129 -P3306 -uroot -p123456 -dplayer --no-check-binlog-format --no-check-replication-filters
Checking if all tables can be checksummed ...
Starting checksum ...
            TS ERRORS  DIFFS     ROWS  CHUNKS SKIPPED    TIME TABLE
05-08T00:12:19      0      0        1       1       0   0.019 player.heartbeat
05-08T00:12:19      0      0        5       1       0   0.017 player.player
05-08T00:12:19      0      1        5       1       0   0.017 player.player_def
05-08T00:12:19      0      0        2       1       0   0.021 player.query_review
mysql> system pt-table-checksum -h192.168.112.129 -P3306 -uroot -p123456 -dplayer --no-check-binlog-format --no-check-replication-filters --replicate-check-only
Checking if all tables can be checksummed ...
Starting checksum ...
Differences on bilery.zoo
TABLE CHUNK CNT_DIFF CRC_DIFF CHUNK_INDEX LOWER_BOUNDARY UPPER_BOUNDARY
player.player_def 1 -5 1   

mysql> SET GLOBAL binlog_format = 'ROW';
Query OK, 0 rows affected (0.00 sec)

mysql> 

     參考: