mysql数据库主备表校验与修复
用pt-table-checksum校驗數據一致性
主從數據的一致性校驗是個頭疼的問題,偶爾被業務投訴主從數據不一致,或者幾個從庫之間的數據不一致,這會令人沮喪。通常我們僅有一種辦法,熱備主庫,然后替換掉所有的從庫。這不僅代價非常大,而且類似治標不治本的方案,讓人十分不安。因此我們需要合適的工具,至少幫我們回答下面三個問題:
- 是從庫延遲導致了用戶看到的數據不一致,還是真的主從數據就不一致?
- 如果不一致,這個比例究竟多大?
- 下次還會出現嗎?
回答清楚這幾個問題,有助于我們決定是否修復,以及修復的方式,還可以幫我們找出不一致的數據,進而定位問題根源。而percona的pt-table-checksum正是我們想要的。
pt-table-checksum簡介
pt-table-checksum是著名的?percona-toolkit?工具集的工具之一。它通過在主庫執行基于statement的sql語句來生成主庫數據塊的checksum,把相同的sql語句傳遞到從庫,并在從庫上計算相同數據塊的checksum,最后,比較主從庫上相同數據塊的checksum值,由此判斷主從數據是否一致。這種校驗是分表進行的,在每個表內部又是分塊進行的,而且pt工具本身提供了非常多的限流選項,因此對線上服務的沖擊較小。
checksum計算原理
1. 單行數據checksum值的計算
pt工具先檢查表的結構,并獲取每一列的數據類型,把所有數據類型都轉化為字符串,然后用?concat_ws()?函數進行連接,由此計算出該行的checksum值。checksum默認采用crc32,你可以自己定義效率更高的udf。
2. 數據塊checksum值的計算
如果一行一行的計算checksum再去和從庫比較,那么效率會非常低下。pt工具選擇智能分析表上的索引,然后把表的數據split成一個個chunk,計算的時候也是以chunk為單位。因此引入了聚合函數?BIT_XOR()?。它的功能可以理解為把這個chunk內的所有行的數據拼接起來,再計算crc32的值,就得到這個chunk的checksum值。sql語句如下:
這其中還有count(*),用來計算chunk包含的行數。每一次對chunk進行checksum后,pt工具都會對耗時進行統計分析,并智能調整下一個chunk的大小,避免chunk太大對線上造成影響,同時也要避免chunk太小而效率低下。
3. 一致性如何保證
當pt工具在計算主庫上某chunk的checksum時,主庫可能還在更新,同時從庫可能延遲使得relay-log中還有與這個chunk數據相關的更新,那該怎么保證主庫與從庫計算的是”同一份”數據?答案是加for update當前讀鎖,這保證了主庫的某個chunk內部數據的一致性。否則,1000個人chekcusm同樣的1000行數據,可能得到1000個不同的結果,你無法避開mvcc的干擾!獲得for update鎖后,pt工具開始計算chunk的checksum值,并把計算結果保存到pt工具自建的結果表中(采用replace into select的方式),然后釋放鎖。該語句最終會傳遞到從庫并執行相同的計算邏輯。
內部工作過程
有了上面關鍵的幾點說明,我們再來看看pt工具的內部工作過程,如下圖:簡單解釋下工作過程:
- 1. 連接到主庫:pt工具連接到主庫,然后自動發現主庫的所有從庫。默認采用show full processlist來查找從庫,但是這只有在主從實例端口相同的情況下才有效。
- 3. 查找主庫或者從庫是否有復制過濾規則:這是為了安全而默認檢查的選項。你可以關閉這個檢查,但是這可能導致checksum的sql語句要么不會同步到從庫,要么到了從庫發現從庫沒有要被checksum的表,這都會導致從庫同步卡庫。
- 5. 開始獲取表,一個個的計算。
- 6. 如果是表的第一個chunk,那么chunk-size一般為1000;如果不是表的第一個chunk,那么采用19步中分析出的結果。
- 7. 檢查表結構,進行數據類型轉換等,生成checksum的sql語句。
- 8. 根據表上的索引和數據的分布,選擇最合適的split表的方法。
- 9. 開始checksum表。
- 10. 默認在chunk一個表之前,先刪除上次這個表相關的計算結果。除非–resume。
- 14. 根據explain的結果,判斷chunk的size是否超過了你定義的chunk-size的上限。如果超過了,為了不影響線上性能,這個chunk將被忽略。
- 15. 把要checksum的行加上for update鎖,并計算。
- 17-18. 把計算結果存儲到master_crc master_count列中。
- 19. 調整下一個chunk的大小。
- 20. 等待從庫追上主庫。如果沒有延遲備份的從庫在運行,最好檢查所有的從庫,如果發現延遲最大的從庫延遲超過max-lag秒,pt工具在這里將暫停。
- 21. 如果發現主庫的max-load超過某個閾值,pt工具在這里將暫停。
- 22. 繼續下一個chunk,直到這個table被chunk完畢。
- 23-24. 等待從庫執行完checksum,便于生成匯總的統計結果。每個表匯總并統計一次。
- 25-26. 循環每個表,直到結束。?
校驗結束后,在每個從庫上,執行如下的sql語句即可看到是否有主從不一致發生:?
select * from percona.checksums where master_cnt <> this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <> ISNULL(this_crc) \G
重要選項
安全選項:
–check-replication-filters 是否檢查復制過濾規則?
–check-slave-tables 檢查是否所有從庫都有被檢查的表和列?
–chunk-size-limit 每個chunk最大不能超過這個大小,超過就忽略它
限速選項:
–check-interval 多久檢查一次主從延遲、主庫負載是否達到上限?
–check-slave-lag 是否只檢查這個從庫的延遲?
–max-lag 最大延遲,超過這個就等待?
–max-load 最大負載,超過這個就等待
過濾選項:
–databases 只檢查某些庫?
–tables 只檢查某些表?
這些過濾選項在修復不一致數據后,檢查修復效果很有用。
其他選項
–resume 因某種原因中斷,下次接著執行,不用從頭開始?
–chunk-time 每個chunk被計算的時間,一般默認為0.5秒
實戰舉例
PTDEBUG=1 ./pt-table-checksum --user=user --password=pass --host=10.10.10.10 --port=3306 --databases=nettedfish --tables=just_do_it --recursion-method=processlist
缺陷和注意事項
- 如果表沒有主鍵或唯一索引,或者干脆沒有任何索引,那么pt工具在chunk表的時候,將無所適從。不過我們已強制在建表的時候,每個表都必須有主鍵。
- –check-binlog-format是默認選項,建議不要關閉它。pt-table-checksum工具自身產生的所有sql語句要基于語句格式同步到從庫,這是由它的實現原理決定的。但是在A-B-C的級聯復制結構中,如果B是行格式的復制,那么B與C的數據一致性校驗就沒法做了。在A上設置該sql語句為語句級并不會把set這個動作記錄到binlog中,這個屬性無法級聯傳遞。
- 主從異構的情況下,checksum語句可能在從庫上執行失敗,即使是索引的不一致。例如sql語句中有force index某個索引,但是從庫的表上沒有這個索引,就會導致卡庫。
總結
pt-table-checksum是校驗主從數據不一致的最好工具。由于MySQL復制自身的缺陷,或主從切換不嚴謹,或備份軟件bug等原因,都可能導致主從數據的不一致。不管你管不管,不一致都在那里,就看數據對你重不重要,重要的話,就定期做下檢查并修復吧。?
且看下回分解:用pt-table-sync修復不一致的數據。
用pt-table-sync修復不一致的數據
percona-toolkit 之 【pt-summary】、【pt-mysql-summary】、【pt-config-diff】、【pt-variable-advisor】說明?http://www.linuxidc.com/Linux/2014-08/104929.htm
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為單位??梢岳斫鉃榘裞hunk內所有行的數據拼接起來,再計算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內部,逐行比較并修復有問題的行。其計算邏輯描述如下(以修復主從結構的數據不一致為例,業務雙寫的情況修復起來更復雜—因為涉及到沖突解決和基準選擇的問題,限于篇幅,這里不介紹):
重要選項
安全選項
—[no]check-triggers 檢查是否有觸發器,有則警告
—[no]foreign-key-checks 默認檢查主外鍵約束,有則警告
—[no]unique-checks 檢查是否有唯一索引,無則警告
過濾選項
—ignore-databases
—ignore-engines
—ignore-tables
其他選項
—replicate=s 與pt-table-checksum結合起來,只修復,而不校驗。使用pt-table-checksum之前校驗的結果—bidirectional 雙向同步。通常都以主庫的數據為準,如果開啟雙向同步,就要定義沖突解決規則,會比較復雜
用法舉例
假設10.55.55.55是主庫,10.73.73.73是它的從庫,端口在3306。
1. 先校驗:
PTDEBUG=1 ./pt-table-checksum --user=user --password=pass --host=10.55.55.55 --port=3306 --databases=elink --tables=my_cms_10 --recursion-method=processlist?2. 根據校驗結果,只修復10.73.73.73從庫與主庫不一致的地方:
PTDEBUG=1 ./pt-table-sync --execute --replicate percona.checksums --sync-to-master h=10.73.73.73,P=3306,u=user,p=pass?3. 修復后,再重新校驗一次。執行第一步的語句即可。
4. 檢查修復結果: 登陸到10.73.73.73,執行如下sql語句返回若為空,則說明修復成功:?select * from percona.checksums where master_cnt <> this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <> ISNULL(this_crc)
注意事項
- 采用replace into來修復主從不一致,必須保證被replace的表上有主鍵或唯一鍵,否則replace into退化成insert into,起不到修復的效果。這種情況下pt-table-sync會采用其他校驗和修復算法,但是效率非常低,例如對所有列的group by然后求count(*)(表一定要有主鍵!)。
- 主從數據不一致需要通過replace into來修復,該sql語句必須是語句級。pt-table-sync會把它發起的所有sql語句都設置為statement格式,而不管全局的binlog_format值。這在級聯A-B-C結構中,也會遇到pt-table-checksum曾經遇到的問題,引起行格式的中繼庫的從庫卡庫是必然。不過pt-table-sync默認會無限遞歸的對從庫的binlog格式進行檢查并警告:?
- 由于pt-table-sync每次只能修復一個表,所以如果修復的是父表,則可能導致子表數據連帶被修復,這可能會修復一個不一致而引入另一個不一致;如果表上有觸發器,也可能遇到同樣問題。所以在有觸發器和主外鍵約束的情況下要慎用。pt-table-sync工具同樣也不歡迎主從異構的結構。pt-table-sync工具默認會進行先決條件的檢查。
- pt-table-sync在修復過程中不能容忍從庫延遲,這正好與pt-table-checksum相反。如果從庫延遲太多,pt-table-sync會長期持有對chunk的for update鎖,然后等待從庫的master_pos_wait執行完畢或超時。從庫延遲越大,等待過程就越長,主庫加鎖的時間就越長,對線上影響就越大。因此要嚴格設置max-lag。
- 對從庫數據的修復通常是在主庫執行sql來同步到從庫。因此,在有多個從庫時,修復某個從庫的數據實際會把修復語句同步到所有從庫。數據修復的代價取決于從庫與主庫不一致的程度,如果某從庫數據與主庫非常不一致,舉例說,這個從庫只有表結構,那么需要把主庫的所有數據重新灌一遍,然后通過binlog同步,同時會傳遞到所有從庫。這會給線上帶來很大壓力,甚至拖垮集群。正確的做法是,先用pt-table-checksum校驗一遍,確定不一致的程度:如果不同步的很少,用pt-table-sync直接修復;否則,用備份先替換它,然后用pt-table-sync修復。 說明: 這實際提供了一種對myisam備份的思路:如果僅有一個myisam的主庫,要為其增加從庫,則可以:先mysqldump出表結構到從庫上,然后啟動同步,然后用pt-table-sync來修復數據。
總結
pt-table-sync工具很復雜也很強大。它修改數據庫的內容,所以可能造成安全事故。為了安全,建議:使用pt-table-checksum定期檢測數據的一致性,并手動重建損壞較為嚴重的從庫,最后才用pt-table-sync修復剩下的從庫。
本文永久更新鏈接地址:?http://www.linuxidc.com/Linux/2014-11/109852.htm
總結
以上是生活随笔為你收集整理的mysql数据库主备表校验与修复的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分享卡通儿童中小学班干竞选PPT模板
- 下一篇: linux cmake编译源码,linu