以前詳細介紹了Mysql主從複製的原理和部署過程,在mysql同步過程當中會出現不少問題,致使數據同步異常。
如下梳理了幾種主從同步中可能存在的問題:
1)slave運行過慢不能與master同步,也就是MySQL數據庫主從同步延遲
MySQL數據庫slave服務器延遲的現象是很是廣泛的,MySQL複製容許從機進行SELECT操做,可是在實際線上環境下,因爲從機延遲的關係,很難將讀取操做轉向到從機。這就致使了有了如下一些潛規則:「實時性要求不高的讀取操做能夠放到slave服務器,實時性要求高的讀取操做放到master服務器」,「從機僅能作前一天的統計類查詢」。
slave滯後即slave不能快速執行來自於master的全部事件,從而不能避免更新slave數據延遲。
mysql的master-slave架構中master僅作寫入、更新、刪除操做,slave作select操做。形成slave滯後的緣由有不少。
slave同步延遲的原理
MySQL的主從複製都是單線程的操做,主庫對全部DDL和DML產生的日誌寫進binlog,因爲binlog是順序寫,因此效率很高。
Slave的IO Thread線程從主庫中bin log中讀取取日誌。
Slave的SQL Thread線程將主庫的DDL和DML操做事件在slave中重放。DML和DDL的IO操做是隨即的,不是順序的,成本高不少。
因爲SQL Thread也是單線程的,若是slave上的其餘查詢產生lock爭用,又或者一個DML語句(大事務、大查詢)執行了幾分鐘卡住了,那麼全部以後的DML會等待這個DML執行完纔會繼續執行,這就致使了延時。也許有人會質疑:主庫上那個相同的DDL也會執行幾分鐘,爲何slave會延時?緣由是master能夠併發執行,而Slave_SQL_Running線程卻不能夠。
slave同步延遲的可能緣由
1--slave的I/O線程推遲讀取日誌中的事件信息;最多見緣由是slave是在單線程中執行全部事務,而master有不少線程能夠並行執行事務。
2--帶來低效鏈接的長查詢、磁盤讀取的I/O限制、鎖競爭和innodb線程同步啓動等。
3--Master負載;Slave負載
4--網絡延遲
5--機器配置(cpu、內存、硬盤)
(主從同步延遲怎麼產生的?)總之,當主庫的TPS併發較高時,產生的DDL數量超過slave一個sql線程所能處理的承受範圍時,主從同步就會產生延時;或者當slave中有大型query語句產生了鎖等待也會產生延時。
如何查看同步延遲
1--能夠經過比對master、slave上的日誌位置
2--經過"show slave status"查看Seconds_Behind_Master的值,這個值表明主從同步延遲的時間,值越大說明延遲越嚴重。值爲0爲正常狀況,正值表示已經出現延遲,數字越大從庫落後主庫越多。
3--使用percona-toolkit的pt-hearbeat工具進行查看。
減小同步延遲的操做方案
1--減小鎖競爭
若是查詢致使大量的表鎖定,須要考慮重構查詢語句,儘可能避免過多的鎖。
2--負載均衡
搭建多少slave,而且使用lvs或nginx進行查詢負載均衡,能夠減小每一個slave執行查詢的次數和時間,從而將更多的時間用於去處理主從同步。
3--salve較高的機器配置
4--Slave調整參數
爲了保障較高的數據安全性,配置sync_binlog=1,innodb_flush_log_at_trx_commit=1等設置。而Slave能夠關閉binlog,innodb_flush_log_at_trx_commit也能夠設置爲0來提升sql的執行效率(這兩個參數很管用)
5--並行複製
即有單線程的複製改爲多線程複製。
從庫有兩個線程與複製相關:io_thread 負責從主庫拿binlog並寫到relaylog, sql_thread 負責讀relaylog並執行。
多線程的思路就是把sql_thread 變成分發線程,而後由一組worker_thread來負責執行。
幾乎全部的並行複製都是這個思路,有不一樣的,即是sql_thread 的分發策略。
MySQL5.7的真正並行複製enhanced multi-threaded slave(MTS)很好的解決了主從同步複製的延遲問題。html
2)slave同步狀態中出現Slave_IO_Running: NO (通常是下面的緣由2形成的)
報錯:Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'mysql
緣由1:清理數據致使主從庫不一樣步(前提是主庫的binlog日誌沒有被暴力刪除或錯誤刪除,即要確保正在使用的那個最新binlog文件在master主庫機器上存在)。 解決辦法: 1)先進入slave中執行:"slave stop;"來中止從庫同步; 2)再去master中執行:"flush logs;"來清空日誌; 3)而後在master中執行:"show master status;"查看下主庫的狀態,主要是日誌的文件和position; 4)而後回到slave中,執行:"CHANGE MASTER TO ......執行同步指令 緣由2:該錯誤發生在從庫的io進程從主庫拉取日誌時,發現主庫的mysql_bin.index文件中第一個文件不存在。出現此類報錯多是因爲你的slave 因爲某種緣由中止了好長一段 時間,當你重啓slave 複製的時候,在主庫上找不到相應的binlog ,會報此類錯誤。或者是因爲某些設置主庫上的binlog被刪除了,致使從庫獲取不到對應的binglog file。 解決辦法: 1)爲了不數據丟失,須要從新進行slave同步操做。 2)注意主庫binlog的清理策略,選擇基於時間過時的刪除方式仍是基於空間利用率的刪除方式。 3)記住最好不要使用"rm -rf"命令刪除binlog file,這樣不會同步修改mysql_bin.index 記錄的binlog 條目。在刪除binlog的時候確保主庫保留了從庫"show slave status" 的Relay_Master_Log_File對應的binlog file。任什麼時候候都不能刪除正在使用的那個最新binlog文件;最好把bin-log文件不要刪除,最好給備份出來。 緣由2的狀況下,使用緣由1的處理方案顯然是解決不了的!此時的解決方案: 在從庫上執行: mysql> stop slave; mysql> reset slave; mysql> start slave; mysql> show slave status \G;
3)slave同步狀態中出現Slave_IO_Running: Connecting
致使這個錯誤的緣由通常是:
1--網絡不通
2--權限問題(鏈接master的用戶名和密碼跟master受權不一致)
3--鏈接時用的log file和pos節點跟"show master status"的結果不一致nginx
4)slave同步狀態中出現Slave_SQL_Running: No ,即slave不一樣步!
解決辦法:
第一種方法:忽略錯誤後,繼續同步。
該方法適用於主從庫數據相差不大,或者要求數據能夠不徹底統一的狀況,數據要求不嚴格的狀況(下面均爲在slave機器上的操做)
mysql> stop slave;
mysql> set global sql_slave_skip_counter =1; //表示跳過一步錯誤,後面的數字可變;或者在my.cnf裏添加slave-skip-errors = all(上面已在配置中添加)
mysql> start slave;
mysql> show slave status\G //查看:
第二種方法:從新作主從,徹底同步
該方法適用於主從庫數據相差較大,或者要求數據徹底統一的狀況
1--master主庫上操做
mysql> flush tables with read lock; //進行鎖表,防止數據寫入。注意該處是鎖定爲只讀狀態,語句不區分大小寫
#mysqldump --lock-all-tables --all-databases --flush-logs --master-data=2 > /root/allsql.sql //主庫徹底備份(若是是指定庫同步,就備份指定庫),注意數據庫備份必定要按期進行,確保數據萬無一失
mysql> show master status; //查看master狀態,注意log file和pos節點,slave同步會用到
# scp mysql.bak.sql root@192.168.1.102:/tmp/ //把備份文件傳到slave從庫機器,進行數據恢復
2--slave從庫操做
mysql> stop slave;
mysql> source /tmp/mysql.bak.sql
mysql> change master to master_host = '192.168.1.101', master_user = 'slave', master_port=3306.......;
mysql> start slave;
mysql> show slave status\G
.......
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
此種方法中最爲關鍵主要有兩步:
①主服務器上鎖表作徹底備份,並滾動日誌;
②從服務器上進行半道恢復.sql
5)slave中繼日誌relay-log損壞?
什麼是中繼日誌?
relay-log存放在從服務器上,從服務器將主服務器的二進制日誌文件拷貝到本身的主機上放在中繼日誌中,而後調用SQL線程按照拷中繼日誌文件中的二進制日誌文件執行以便就可達到數據的同步 。
如何中繼日誌避免:
mysql 5.6版本後,在my.cnf文件中開啓relay_log_recover=1便可避免。數據庫
6)slave鏈接超時且從新鏈接頻繁
如有多少slave,且沒有設置server_id或兩個slave設置相同的server_id,將有可能會出現服務器的ID衝突。這種狀況下,其中一臺slave可能會頻繁超時或丟失後從新鏈接序列。
因此必定要確保每臺slave及master在my.cnf中都要設置不同的server_id。安全
7)主庫與從庫使用不一樣的存儲引擎形成不一樣步bash
8)從庫同步時,提示表不存在
錯誤:Last_Error: Error executing row event: 'Table 'test.t1' doesn't exist'
解決方法:在從庫重建這張表。服務器
9)max_allowed_packet設置太小致使slave報錯
max_allowed_packet默認是16M,主從庫的max_allowed_packet值和備庫上的不匹配。
在這狀況下,主庫可能會記錄一個備庫認爲過大的包。當備庫獲取到該二進制日誌事件時,可能會碰到各類問題,如無限報錯和重試、中繼日誌損壞等。
具體表現:
從庫的Slave_IO_Thread死掉了,查看後,出現如下錯誤提示:
Got a packet bigger than 'max_allowed_packet' bytes
很明顯是因爲max_allowed_packet的設置過小致使的,而後查檢主從庫上的設置,主庫的設置大於從庫,由於max_allowed_packet是動態參數,先調整從庫上的max_allowed_packet 與主庫相同,從新單獨啓動I/O線程就正常了。
原理說明:binlog的事件以RBR格式記錄,且當前的事件長度大於了從庫的max_allowed_packet, 致使沒法Slave IO不能正常讀取master binlog event.網絡
10)在master上刪除一條記錄時出現的故障
在master上刪除一條記錄後,slave上因找不到這條記錄而報錯。
解決方法:
因爲主庫上已經對這條語句進行了刪除操做,故能夠跳過。
在這種狀況下,說明主從同步可能數據會有不一致的狀況發生,因此須要使用pt-table-checksum進行數據庫一致性比對。
(參考:mysql主從同步(3)-percona-toolkit工具(數據一致性監測、延遲監控)使用梳理)多線程
11)在master更新一條記錄,而slave卻找不到。
主從數據不致時,master有某條記錄,但在salve上沒有這條記錄,若在master上進行更新這條記錄,則在slave中可能報錯。
解決方法:
1--根據從庫發生異常的位置,查主庫上的二進制日誌。
2--根據主庫二進制日誌信息,找到更新後的整條記錄。
3--在從庫上執行在主庫上找到的記錄信息,進行insert操做。
4--跳過這條語句,再同步slave。
5--使用pt-table-checksum查看主從庫表數據否一致。
12)刪除登陸mysql後的操做記錄
[root@mysql ~]# ll /home/mysql/.mysql_history -rw------- 1 mysql mysql 1255 Jun 15 18:18 /home/mysql/.mysql_history [root@mysql ~]# >/home/mysql/.mysql_history
13)同步時出現報錯"Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'"
在從機mysql上查看slave狀態,報錯以下: Mysql> show slave status\G; ...... Slave_IO_Running: No Slave_SQL_Running: Yes ...... Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file' 解決辦法: 在主機mysql上執行: Mysql> FLUSH TABLES WITH READ LOCK; Mysql> flush logs; Mysql> show master status; 記下File, Position。 而後在從機mysql上執行同步操做(根據上面記住的File和Position) Mysql> stop slave; Mysql> change master to master_host='主機mysqlip',master_user='受權同步的用戶',master_password='受權同步密碼',master_log_file='記下的File',master_log_pos=記下的Position; Mysql> start slave; Mysql> show slave status\G; ...... Slave_IO_Running: No Slave_SQL_Running: Yes 而後在主機mysql上進行解鎖 mysql> unlock tables;
14)服務器重啓或mysql服務重啓後,如何恢復mysql主從同步關係
當mysql主從同步順利完成後,若是重啓服務器或mysql服務重啓後,恢復mysql主從同步關係的正確步驟: 1)主機mysql和從機mysql都要啓動mysql服務 # /etc/init.d/mysql start 2) 在從機mysql上進行slave恢復操做 mysql> stop slave; Query OK, 0 rows affected (0.08 sec) mysql> start slave; Query OK, 0 rows affected (0.04 sec) mysql> show slave status \G; ...... Slave_IO_Running: Yes Slave_SQL_Running: Yes .....
mysql主從同步(跨機房狀況)不一致問題
1) 網絡的延遲
因爲mysql主從複製是基於binlog的一種異步複製,經過網絡傳送binlog文件,理所固然網絡延遲是主從不一樣步的絕大多數的緣由,特別是跨機房的數據同步出現這種概率很是的大,因此作讀寫分離,注意從業務層進行前期設計。
2) 主從兩臺機器的負載不一致
因爲mysql主從複製是主數據庫上面啓動1個io線程,而從上面啓動1個sql線程和1個io線程,當中任何一臺機器的負載很高,忙不過來,致使其中的任何一個線程出現資源不足,都將出現主從不一致的狀況。
3) max_allowed_packet設置不一致
主數據庫上面設置的max_allowed_packet比從數據庫大,當一個大的sql語句,能在主數據庫上面執行完畢,從數據庫上面設置太小,沒法執行,致使的主從不一致。
4) key自增鍵開始的鍵值跟自增步長設置不一致引發的主從不一致。
5) mysql異常宕機狀況下,若是未設置sync_binlog=1或者innodb_flush_log_at_trx_commit=1頗有可能出現binlog或者relaylog文件出現損壞,致使主從不一致。
6) mysql自己的bug引發的主從不一樣步。
7) 版本不一致,特別是高版本是主,低版本爲從的狀況下,主數據庫上面支持的功能,從數據庫上面不支持該功能。
以上就是常見的一些主從不一樣步的狀況。基於以上狀況,先保證max_allowed_packet、自增鍵開始點和增加點設置一致,再者犧牲部分性能在主上面開啓sync_binlog。
對於採用innodb的庫,推薦在配置文件中添加下面內容:
innodb_flush_logs_at_trx_commit = 1 innodb-support_xa = 1
同時在從數據庫的配置文件中再多添加下面兩個參數:
skip_slave_start read_only