一招教你如何修復MySQL slave中繼日誌損壞問題

【摘要】MySQL的Crash safe slave是指slave crash後,把slave從新拉起來能夠繼續從Master進行復制,不會出現複製錯誤也不會出現數據不一致。html

PS:華爲雲數據庫特惠專場鉅惠來襲,全場10元起購,直降108000元!新購滿額送P30 Pro,點此搶購mysql

Contentssql

1 背景數據庫

2 Relay log的獲取與應用多線程

2.1 源碼分析app

2.1.1 配置參數relay_log_recovery=OFF重啓後,slave機制與源碼源碼分析

2.1.2 配置參數relay_log_recovery=ON重啓後,slave機制與源碼線程

3 修復計劃日誌

3.1 具體實現思路code

3.2 流程圖

4 總結

1 背景

MySQL的Crash safe slave是指slave crash後,把slave從新拉起來能夠繼續從Master進行復制,不會出現複製錯誤也不會出現數據不一致。爲保證crash safe slave,需解決因爲未同步刷盤致使的binlog文件接收位置和實際不一致或者relay log文件不完整的問題,所以relay_log_recovery爲ON是必需配置參數之一。可是設置relay_log_recovery爲ON會致使MySQL正常重啓或者宕機恢復時以備庫的SQL線程執行位置爲起點從新向主庫請求binlog,可能因爲以前主備時延大,請求點的binlog已被主機清除,最終致使主備複製關係異常,所以設置relay_log_recovery爲OFF是生產環境常見的設置。可是,此設置在OS的oom-killer事件以及OS異常斷電等狀況可能致使備庫relay log的部分event不完整, MySQL重啓後,SQL線程回放執行到不完整的event就會致使主備複製關係中斷,查看error.log能夠看到相似以下的錯誤信息:

2 Relay log的獲取與應用

MySQL支持的複製方式按鏈接協議來區分,能夠分爲

• 非GTID模式,經過binlog文件名和文件的偏移來決定複製位點信息

• GTID模式,經過GTID信息來決定複製位點信息

2.1 源碼分析

2.1.1 配置參數relay_log_recovery=OFF重啓後,slave機制與源碼

1)基於binlog複製(非GTID)模式,MySQL重啓後,重連主庫時,備庫的IO線程讀取slave_master_info表記錄的master_log_name以及master_log_pos值向主庫請求binlog。

1.  |-init_slave()  
2.  /* read all the slave repositories on disk (either in FILE or TABLE form) and create corresponding slave info objects 
3.  */  
4.    |-Rpl_info_factory::create_slave_info_objects  
5.       |-load_mi_and_rli_from_repositories  
6.         |-Master_info::mi_init_info()  
7.  /* Creates or reads information from the repository, initializing the Master_info.*/     
8.           |-Master_info::read_info()  
9.             |-get_info()  
10.            //初始化mi master_log_pos && master_log_name

備庫的SQL線程讀取slave_relay_log_info表記錄的relay_log_name以及relay_log_pos值開始應用relay log。

1.  |-init_slave()  
2.     |-Rpl_info_factory::create_slave_info_objects  
3.       |-load_mi_and_rli_from_repositories  
4.         |-Relay_log_info::rli_init_info  
5.           |-Relay_log_info::read_info()  
6.           //rli group_relay_log_pos && group_master_log_pos &&               
7.           group_relay_log_name && group_master_log_name

2)基於GTID複製模式,MySQL重啓後,重連主庫時,備庫的IO線程經過讀取mysql.gtid_executed表以及binlog文件獲取Executed_Gtid_Set,經過讀取realy_log文件獲取Retrieved_Gtid_Set,並將二者的並集發送到主庫請求binlog。

1.  mysqld_main ()  
2.   //讀持久化介質mysql.gtid_executed表  
3.   |-Gtid_state::read_gtid_executed_from_table ()  
4.   //讀持久化介質binlog  
5.   |-MYSQL_BIN_LOG::init_gtid_sets ()  
6.   |-init_slave ()  
7.    |-Rpl_info_factory::create_slave_info_objects ()  
8.     |-load_mi_and_rli_from_repositories ()  
9.      |-Relay_log_info::rli_init_info ()  
10.      |-MYSQL_BIN_LOG::init_gtid_sets ()  
11.       |-Relay_log_info::init_relay_log_pos ()

對於備庫的SQL線程其應用relay log的起始從slave_relay_log_info表讀取,其執行過程若是發現事務的gtid已經存在,則ev->apply_event時就會忽略這個事務,保證不會重複執行同一個事務。

2.1.2 配置參數relay_log_recovery=ON重啓後,slave機制與源碼

當參數relay_log_recovery爲ON,不管是單線程仍是多線程回放,MySQL正常重啓或者宕機恢復時以備庫的SQL線程執行位置爲起點從新向主庫請求binlog。基於binlog複製發送的是slave_relay_log_info表讀取relay_log_name以及Relay_log_pos值。基於GTID複製模式發送的是備庫執行完的gtid_sets。

1.  static void recover_relay_log(Master_info *mi)  
2.  {  
3.    Relay_log_info *rli=mi->rli;  
4.    // Set Receiver Thread's positions as per the recovered Applier Thread.  
5.    mi->set_master_log_pos(max<ulonglong>(BIN_LOG_HEADER_SIZE,  
6.                                          rli->get_group_master_log_pos()));  
7.    mi->set_master_log_name(rli->get_group_master_log_name());  
8.    rli->set_group_relay_log_name(rli->relay_log.get_log_fname());  
9.    rli->set_event_relay_log_name(rli->relay_log.get_log_fname());  
10.   rli->set_group_relay_log_pos(BIN_LOG_HEADER_SIZE);  
11.   rli->set_event_relay_log_pos(BIN_LOG_HEADER_SIZE);  
12. }

3 修復計劃

當備庫配置master_info_repository與relay_log_info_repository都爲TABLE時,對於SQL線程而言,會在一個事務提交的同時更新表slave_relay_log_info,其獲得原子性保證,即SQL線程執行位置始終是對的。但異常宕機可能致使丟失master info,IO線程會dump到重複的日誌和SQL線程可能會重複執行同一個事務,這樣就會致使主備複製出錯,這樣對於非gtid複製的模式,因此爲保證主備正常且數據一致,relay_log_recovery=ON爲Crash safe slave必需參數。

可是若是開啓了gtid就能夠避免上述問題,GTID複製協議保證了數據的一致性,且ev->apply_event時會忽略已執行的事務。所以對於備庫設置爲relay_log_recovery=OFF的配置,relay log文件中可能存在的損壞的event可直接清除,避免出現主備複製關係異常。

3.1 具體實現思路

方案:

一、在MySQL啓動初始化過程當中進行損壞relay log(不完整event)修復。

二、在初始化Gtid_sets的MYSQL_BIN_LOG:init_gtid_set()處,若配置參數設置了功能啓動開關rds_recovery_relay_log=ON,則進入下面流程。

三、掃描relay log時,判斷其是不是正常關閉,非正常關閉則進入修復檢測流程。

四、讀取非正常關閉relay log文件,遍歷其event,並記錄更新合法的event的位置,若存在非完整event則退出,返回記錄的最新合法event位置。

四、根據返回的合法event位置截斷relay log,清除文件中損壞的部分。

五、後續流程正常進行

3.2 流程圖

4 總結

設置rds_relay_log_recovery參數設置爲ON,可解決OS宕機等狀況致使MySQL備庫的relay log的不完整致使主備異常狀況。建議使用方法,在OS宕機等狀況,重啓mysql服務時,設置開啓rds_relay_log_recovery=ON,可預防relay_log_recovery=ON的潛在缺點即自sql thread執行完的gtid起請求的binlog已被master purge。

最後,華爲雲數據庫特惠專場鉅惠來襲,比自建好用還省錢,全場10元起購,直降108000元,新購滿額送P30 Pro,點此搶購

相關文章
相關標籤/搜索