《MySQL主從一致性對比》要點:
本文介紹了MySQL主從一致性對比,希望對您有用。如果有疑問,可以聯系我們。
原文:http://www.jianshu.com/p/54192d03274d
作者:何約什
我們平臺中上線了大量的MySQL業務,但是每個MySQL業務中主從數據庫之間的一致性,我們基本不可知,而且由于性能原因的考慮,我們99%左右的MySQL中的兩個影響數據一致性的參數innodb_flush_log_at_trx_commit設置為1,并且sync_binlog設置為0。這樣,一旦出現機器重啟時,MySQL數據庫的主從節點之間就會存在數據不一致性的情況。
數據不一致性出現以后,一方面會影響業務,另外一方面DBA經常會收到告警:數據庫同步錯誤。為了解決這個問題,我們要實現平臺級的數據庫一致性對比功能,在平臺中定期對必要的業務進行定期的一致性檢測和數據修復就非常有必要性了。
所以最近研究了一下MySQL的一致性對比和修復工具:pt-table-checksum和pt-table-sync。下面分別對pt-table-checksum和pt-table-sync的原理做一下簡單介紹。
pt-table-checksum的原理:
校驗表的結構如下:
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, PRIMARY KEY (db, tbl, chunk), INDEX ts_db_tbl (ts, db, tbl) ) ENGINE=InnoDB;
把數據進行分塊,先計算第一個塊的數據的校驗和,并寫入到校驗表中的this_crc和this_cnt字段中,這條檢核和的SQL語句會傳遞到從庫,從庫會收到后計算自己的SQL語句;
然后讀取主庫的中校驗表的this_crc和this_cnt字段數據,生成SQL語句更新checksums表中的master_crc和master_cnt字段,從庫收到SQL語句以后,會把從庫中的checksums表的master_crc和master_cnt字段進行更新,這樣在從庫中就得到了主庫的校驗和以及自己的數據校驗和;
輪詢整張表,重復2,3步把所有的塊計算完成;
通過下面這條語句就可以得出主庫和從庫的各個塊是否一致
select * from checksums where master_cnt <>this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <>ISNULL(this_crc)
對每一個從庫,每一個表,循環進行如下校驗和修復過程。
對每一個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。
直到這個從庫上所有的表修復結束。開始修復下一個從庫。
平臺一致性對比方案
有了這兩個一致性對比工具,就很容易在平臺中搭建一致性對比和數據修復了,我們在選擇一個業務進行對比,通過指令下發就能夠對業務進行一致性對比,并從平臺中查詢對比的進行和最終對比的結果,依據對比結果,決定是否進行數據修復。
問題出現了
測試的過程中,我們發現一旦表比較大的情況下,并且不一致的情況比較嚴重的情況下,會造成對比非常緩慢,最壞的情況20G的數據對比和修復需要花費6個小時,而且整個對比過程有可能會影響線上正在運行的業務。為了減少這種大表對比和修復的影響,我們必須要針對大表提出我們自己的對比和修復方案來。
解決思路
1.首先需要解決的是要找出數據庫中的大表
我們可以通過指令show table status from DBNAME 獲取數據庫中的表的信息,可以獲取到表的行數信息,就可以知道那些表是大表了。但是這條指令有可能會產生副作用,因為這條sql語句會訪問information_schema下的表,訪問這些表的時候,如果是innodb,這些innodb可能會自動做更新索引統計的操作,這可能會造成大量磁盤操作和緩存數據的換出,為了減少副作用,我們可以在執行show table status from DBNAME之前,先執行set global innodb_stats_on_metadata=0,來防止innodb的“順手”操作。
2.大表對比和修復方案
大表的數據量大,所以我們想到的方案就是大數據計算平臺:hadoop和spark平臺。所以我們的對比過程圖如下所示:
導出主從數據庫表中的數據 ---> 上傳到Hadoop ---> 用大數據平臺對比出不同的key值 ---> 不同的key值采用pt-table-sync類似的原理一行行再次對比,過濾掉相同key ----> 剩下不同的key進行修復
通過以上手段流程就能完美的把大量的數據計算從MySQL遷移到大數據平臺,剩下的少量不一致的key值,再到MySQL上比對,從而避免了對業務數據庫的影響。大數據庫對比有兩種選擇MapReduce以及Spark,相對來說Spark會比MapReduce簡單很多,所以我們選擇Spark,
下面簡單介紹一下大概的對比方案的實施步驟:
1 導出文件
采用select * into outfile從mysql中導出要對比的表,假設我們從master中導出了一張表,導出文件為:master.txt,內容為:
1,"abc","dddddd" 2,"ef","adddd"
從slave中導出一張表,導出文件為:slave.txt,內容為:
1,"abc","tttt"
2,"ef","fffff"
2 上傳文件到hdfs中
hadoop fs -copyFromLocal master.txt /
hadoop fs -copyFromLocal slave.txt /
3 采用下面的spark腳本計算不同的key值
val rddMaster = sc.textFile("/master.txt").map(x =>(x.split(",")(0), x)) // 假設第一個字段是主鍵
val rddSlave = sc.textFile("/slave.txt").map(x =>(x.split(",")(0), x))
val difference = rddMaster.cogroup(rddSlave).filter(x=> x._2._1 != x._2._2 )
val differenceKey = difference.keys()
differenceKey.collect
通過三面的三個步驟我們就能夠得出不同的key值有哪些了。
上面的代碼非常簡單,只是提供一個思路,對于具體的情況肯定會復雜一些,如有多個主鍵的情況,依據主鍵數據中包含了分割符號等等情況,這里就不對這些情況進行細說了。
轉載請注明本頁網址:
http://www.snjht.com/jiaocheng/35.html