MySQL主從複製常遇到的幾個坑
主從複製架構圖如下:
主庫有資料變更時,會通知備庫的io執行緒,io執行緒建立一個TCP長連線,接下來主庫的binlog dump執行緒會推送主庫的binlog。在進行完一次HTTP操作後保持該TCP連線(HTTP/1.1起預設使用長連線)。只要Server端或Client端不提出關閉請求,或存在其他異常情況,兩者間的連線將持續下去。
主庫的worker執行緒在寫binlog的時候是併發工作的,而主庫的dump執行緒和從庫的IO執行緒在讀和收binlog的過程中是單執行緒工作的(5.7版本之後支援多執行緒)。因此高併發的情況下,從庫很有可能跟不上主庫的進度(非同步複製)。
主從同步環境下,由於主備庫搭建複製關係時,備庫“不乾淨”,導致有可能遇到備庫無法執行某個binlog event的情況,此時在確定binlog中該event的影響之後,可以採用:1)在從庫上 set sql_log_bin=OFF; [建立缺失的記錄;] set sql_log_bin=ON; 2)pt-slave-restart 跳過N個錯誤:--skip-count=N、跳過指定錯誤碼:--error-numbers=1062; 3)set global sql_slave_skip_counter=N;跳過N個binlog event。
特別需要指出的是:set global sql_slave_skip_counter,當第N個event存在於某個事務,則該event所在的整個事務也將被跳過。
我們在互動介面內輸入的一句SQL,表現在binlog中的記錄就有所不同了。
如下截取了一段row格式記錄的binlog:
# at 8982883 #170803 16:35:08 server id 23712 end_log_pos 8982951 Query thread_id=1601 exec_time=0 error_code=0 SET TIMESTAMP=1501749308/*!*/; BEGIN /*!*/; # at 8982951 # at 8983010 #170803 16:35:08 server id 23712 end_log_pos 8983010 Table_map: `demo`.`heartbeat` mapped to number 35 #170803 16:35:08 server id 23712 end_log_pos 8983156 Update_rows: table id 35 flags: STMT_END_F BINLOG ' POCCWROgXAAAOwAAAOIRiQAAACMAAAAAAAEABGRlbW8ACWhlYXJ0YmVhdAAGDwMPCA8IBmgA/AP8 Azw= POCCWRigXAAAkgAAAHQSiQAAACMAAAAAAAEABv//8BoyMDE3LTA4LTAzVDE2OjM1OjA3LjAwMTQw MKBcAAAQAG15c3FsLWJpbi4wMDAwMzE3EIkAAAAAAPAaMjAxNy0wOC0wM1QxNjozNTowOC4wMDE2 MjCgXAAAEABteXNxbC1iaW4uMDAwMDMxYxGJAAAAAAA= '/*!*/; # at 8983156 #170803 16:35:08 server id 23712 end_log_pos 8983183 Xid = 158813 COMMIT/*!*/;
再看一段relay log中的binlog event group
mysql> show relaylog events in "mysql-relay-bin.000051" from 5867832 limit 5 \G
*************************** 1. row ***************************
Log_name: mysql-relay-bin.000051
Pos: 5867832
Event_type: Query
Server_id: 23712
End_log_pos: 10170351
Info: BEGIN
*************************** 2. row ***************************
Log_name: mysql-relay-bin.000051
Pos: 5867900
Event_type: Table_map
Server_id: 23712
End_log_pos: 10170410
Info: table_id: 35 (demo.heartbeat)
*************************** 3. row ***************************
Log_name: mysql-relay-bin.000051
Pos: 5867959
Event_type: Update_rows
Server_id: 23712
End_log_pos: 10170556
Info: table_id: 35 flags: STMT_END_F
*************************** 4. row ***************************
Log_name: mysql-relay-bin.000051
Pos: 5868105
Event_type: Xid
Server_id: 23712
End_log_pos: 10170583
Info: COMMIT /* xid=179683 */
*************************** 5. row ***************************
Log_name: mysql-relay-bin.000051
Pos: 5868132
Event_type: Query
Server_id: 23712
End_log_pos: 10170651
Info: BEGIN
5 rows in set (0.00 sec)
可以看到對heartbeat表的一次update操作,對應binlog中記錄有如下4條event:
1、BEGIN
2、Table_map
3、Update_rows
4、COMMIT
主從複製過濾引數優先考慮:replicate-wild-ignore-table
主庫的max_allowed_packet需要小於等於備庫的max_allowed_packet。
否則當binlog為ROW格式,本來資料量就大,此時又有大事務在主庫執行完之後,容易出現無法傳輸到備庫執行的情況。
提示:Slave_IO_Running: No
Got a packet bigger than 'max_allowed_packet' bytes
啟用帶加密連線的主從複製
https://dev.mysql.com/doc/refman/5.5/en/replication-solutions-secure-connections.html