萬盛學電腦網

 萬盛學電腦網 >> 數據庫 >> mysql教程 >> MySQL數據庫主從 如果主掛了如何自動將主切換到從

MySQL數據庫主從 如果主掛了如何自動將主切換到從

MySQL主從數據庫結構為1主2從,如果在主數據庫1出現異常時要自動把主數據庫切換到2從數據庫,我們應該如何操作?

問題描述:
結構的1主2從,機器名分別為M1、S1、S2。使用keepalived+haproxy,將M1、S1做心跳,在M1正常的情況下,S1只負責讀,如果M1掛了,則讓S1變成讀+寫。
問題如下:在M1掛掉,S1升級成新主機的情況下,S2如何能夠自動將主機變更為S1,並且知道S1接手以後,新的日志文件的名稱和position。



最佳回答:

備庫如何發起DUMP請求
引入GTID,最大的好處當然是我們可以隨心所欲的切換主備拓撲結構了。在一個正常運行的復制結構中,我們可以在備庫簡單的執行如下SQL:


CHANGE MASTER TO MASTER_USER=’$USERNAME’, MASTER_HOST=’ ‘, MASTER_PORT=’ ‘, MASTER_AUTO_POSITION=1;

打開GTID後,我們就無需指定binlog文件或者位置,MySQL會自動為我們做這些事情。這裡的關鍵就是MASTER_AUTO_POSITION。IO線程連接主庫,可以大概分為以下幾步:
1.IO線程在和主庫建立TCP鏈接後,會去獲取主庫的uuid(get_master_uuid),然後在主庫上設置一個用戶變量@slave_uuid(io_thread_init_commands)

2.之後,在主庫上注冊SLAVE(register_slave_on_master)

在主庫上調用register_slave來注冊備庫,將備庫的host,user,password,port,server_id等信息記錄到slave_list哈希中。

3.調用request_dump,開始向主庫請求數據,這裡分兩種情況:
MASTER_AUTO_POSITION=0時,向主庫發送命令的類型為COM_BINLOG_DUMP,這是傳統的請求BINLOG的模式
MASTER_AUTO_POSITION=1時,命令類型為COM_BINLOG_DUMP_GTID,這是新的方式。
這裡我們只討論第二種。第二種情況下,會先去讀取備庫已經執行的gtid集合
quoted code in rpl_slave.cc :
if (command == COM_BINLOG_DUMP_GTID)

{
// get set of GTIDs
Sid_map sid_map(NULL/*no lock needed*/);
Gtid_set gtid_executed(&sid_map);
global_sid_lock->wrlock();
gtid_state->dbug_print();
if (gtid_executed.add_gtid_set(mi->rli->get_gtid_set()) != RETURN_STATUS_OK ||
      gtid_executed.add_gtid_set(gtid_state->get_logged_gtids()) !=
      RETURN_STATUS_OK)




構建完成發送包後,發送給主庫。

在主庫上接受到命令後,調用入口函數com_binlog_dump_gtid,流程如下:



1.slave_gtid_executed.add_gtid_encoding(packet_position, data_size) ;讀取備庫傳來的GTID SET
2.讀取備庫的uuid(get_slave_uuid),被根據uuid來kill僵屍線程(kill_zombie_dump_threads)
這也是之前SLAVE IO線程執行SET @SLAVE_UUID的用處。
3.進入mysql_binlog_send函數:
         |?>調用MYSQL_BIN_LOG::find_first_log_not_in_gtid_set,從最後一個Binlog開始掃描,獲取文件頭部的PREVIOUS_GTIDS_LOG_EVENT,如果它是slave_gtid_executed的子集,保存當前binlog文件名,否則繼續向前掃描。
         這一步的目的就是為了找出備庫執行到的最後一個Binlog文件。
         
         |?>從這個文件頭部開始掃描,遇到GTID_EVENT時,會去判斷該GTID是否包含在slave_gtid_executed中:
                         Gtid_log_event gtid_ev(packet->ptr() + ev_offset,
                                 packet->length() ? checksum_size,
                                 p_fdle);
                          skip_group= slave_gtid_executed->contains_gtid(gtid_ev.get_sidno(sid_map),
                                                     gtid_ev.get_gno());
         主庫通過GTID決定是否可以忽略事務,從而決定執行開始的位置


注意,在使用MASTER_LOG_POSITION後,就不要指定binlog的位置,否則會報錯。

copyright © 萬盛學電腦網 all rights reserved