mysql集群數據一致性校驗


      目前,mysql在互聯網行業使用地如火如荼,很多大型網站都在使用MySQL數據庫,通過搭建mysql主備集群,實現高性能,高可用的存儲方案。mysql集群的共同特性是通過復制來實現主備間的同步,保證主備數據的一致性。這樣才能保證讀寫分離,備庫為主庫分擔壓力,提高整個集群的可用性和性能。

     為什么需要數據一致性校驗?由於大部分搭建mysql服務的都是PC集群,尤其是在集群達到一定規模后,硬件出故障幾乎是必然的。mysql復制是異步復制,當主機出現故障時,就會出現丟數據的可能,造成主備數據不一致,無法正常對外提供服務。另外,當現有的PC集群容量不足時,需要對集群擴容,擴容就涉及到數據遷移。遷移一般都包括全量和增量,在不停服務的情況下,當遷移完數據后,需要校驗數據的一致性,保證遷移后不對業務造成影響。

     什么是數據一致性?這里僅僅針對mysql,或是關系型數據庫,一致性主要包括兩方面,表結構一致和數據內容一致。一般情況下,表結構變更相對是少的,而且不一致的概率也很小,即使檢查,也相對容易;而導致數據內容不一致的情況很多,所以我們更關心的數據內容的一致性。

      如何實現數據一致性校驗?一種思路就是逐行逐字段比較主庫和備庫的表;另外一種思路是,不逐行逐字段比較,取而代之的是分別對主庫和備庫計算校驗和,通過判斷校驗和是否相同,確定主備庫數據是否一致。兩種思路都很簡單,第一種思路正確性高,但性能比較差,因為返回大量的結果集導致大量的網絡IO和磁盤IO;而第二種思路則恰好相反,性能會更好,少了IO,多消耗了一些CPU資源(計算校驗和),正確性不如第一種思路。但是考慮到生產環境下,數據時時刻刻都是動態變化的,就沒那么簡單了。通過對表加鎖,可以保證我們在校驗時,數據是靜態的,待我們順利完成校驗后,再解鎖。mysql自帶命令CHECKSUM TABLE,就是通過鎖表方式來保證數據是靜態的。這種方式對於小表,訪問量小的表還好,若表非常大,校驗需要很長時間,生產環境是不能容忍的。既然要保持靜態就需要鎖表,可不可以縮短鎖表時間呢?pt-table-checksum通過將表分片,每次只對一部分行上鎖,這樣在校驗過程中,一時刻只有部分行被鎖住,減少對業務的影響。

     目前業界使用比較廣泛的是percona公司的pt-table-checksum,下文我將詳細介紹該工具的使用和原理,並分析其不足以及可以改進的地方。

     pt-table-checksum工具通過在主庫上執行一個校驗和的sql語句,然后通過復制,相同語句會在從庫執行(pt-table-checksum要求復制工作在語句級復制模式下)。通過replace...select語句將校驗和結果存儲在結果表,然后對比主庫和從庫的相同塊的記錄數目和校驗和,判斷主備庫數據是否一致。這里要注意的是,  pt-table-checksum 不是對一個表僅作一個校驗和,因為如果表特別大,將會對DB造成很大的負載,影響正常業務。一個表一個校驗和就退化到mysql自帶命令CHECKSUM TABLE了,不僅需要鎖表,而且不准確。pt-table-checksum將表按用戶設置的塊大小,將表分成若干份,然后對每個塊計算一個校驗和。這樣即使表特別大,分塊后也只會鎖住部分記錄,對DB的負載壓力也大大降低。由於多個表校驗可以並發,可以大大提高校驗效率,通過參數-max-load可以防止load過大。

     pt-table-checksum基本能滿足我們的日常需求,但是它還有一些需要完善的地方,首先,僅僅支持表粒度的並發,當檢查一個大表時,需要耗費大量的時間,另外多表並行執行時,並行度也不能通過參數的設置,而是通過--max-load間接設置。其次,通過分塊生成校驗和雖然加快了校驗速度,但1000行算一個4字節的校驗值(默認是一個塊1000),產生沖突的可能性很大,即使pt-table-checksum設計的校驗和算法很復雜。最后,僅僅塊粒度的不一致還不夠,我們需要精確的知道到底是哪一條記錄,甚至哪一列不一致,並且給出訂正語句,所以哪位同學有興趣,還可以對其進行進一步優化。

     最后,我簡單介紹下pt-table-checksum的使用,關於里面的參數的配置我就不一一列舉了,感興趣的同學可以參考http://www.percona.com/doc/percona-toolkit/2.2/pt-table-checksum.html

1.創建用於校驗的用戶,並授權

grant all privileges on *.* to ptcheck@'%' identified by 'ptcheck';  

2.測試table_pt_check表結構

Create Table: CREATE TABLE `table_pt_check` (

  `c1` int(11) NOT NULL AUTO_INCREMENT,

  `c2` int(11) DEFAULT NULL,

  PRIMARY KEY (`c1`)

) ENGINE=InnoDB AUTO_INCREMENT=26672747 DEFAULT CHARSET=utf8

3.校驗chuck庫中 table_pt_check

pt-table-checksum --host='127.0.0.1' --user='ptcheck' --password='ptcheck' --port=3306 --databases='chuck' --tables='table_pt_check' --replicate=test.checksums

--replicate=test.checksums,指定校驗結果存儲在test庫中的checksums中。通過上述3個步驟就能檢查主備庫的數據是否一致了。

 

校驗結果存儲表結構如下:

Create Table: CREATE TABLE `checksums` (

  `db` char(64) NOT NULL, //庫名

  `tbl` char(64) NOT NULL,  //表名

  `chunk` int(11) NOT NULL,  //分塊號

  `chunk_time` float DEFAULT NULL, //分塊執行時間

  `chunk_index` varchar(200) DEFAULT NULL, //分塊使用的索引,主鍵索引或唯一索引

  `lower_boundary` text,  //分塊的下界值

  `upper_boundary` text, //分塊的上界值

  `this_crc` char(40) NOT NULL, //分塊的哈希值

  `this_cnt` int(11) NOT NULL, //分塊的記錄數目

  `master_crc` char(40) DEFAULT NULL, //master上分塊的哈希值

  `master_cnt` int(11) DEFAULT NULL, //master上分塊的記錄數目

  `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

  PRIMARY KEY (`db`,`tbl`,`chunk`),

  KEY `ts_db_tbl` (`ts`,`db`,`tbl`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8

校驗主備是否一致的SQL如下:

SELECT db,

       tbl,

       Sum(this_cnt) AS total_rows,

       Count(*) AS chunks

FROM test.checksums

WHERE ( master_cnt <> this_cnt

          OR master_crc <> this_crc

          OR Isnull(master_crc) <> Isnull(this_crc) )

GROUP BY db, tbl; 

通過--explain參數可以展示pt-table-checksum在執行過程的SQL

replace INTO `test`.`checksums` (db, tbl, chunk, chunk_index, lower_boundary, upper_boundary, this_cnt, this_crc)

select 'chuck', 'table_pt_check', '7', 'PRIMARY', '21685456', '26100570', COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `c1`, `c2`, CONCAT(ISNULL(`c2`)))) AS UNSIGNED)), 10, 16)), 0) AS crc FROM `chuck`.`table_pt_check` FORCE INDEX(`PRIMARY`) WHERE ((`c1` >= '21685456')) AND ((`c1` <= '26100570'))

注意:計算校驗和的關鍵函數BIT_XOR,通過這個聚合函數,將分塊中每一行每一列的納入計算對象,理論上保證了通過一個校驗和可以判斷主備分塊數據是否一致。


免責聲明!

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



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