久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

MySQL半同步復制的示例分析

146次閱讀
沒有評論

共計 4982 個字符,預計需要花費 13 分鐘才能閱讀完成。

這篇文章主要介紹 MySQL 半同步復制的示例分析,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

代碼分析

int repl_semi_report_commit(Trans_param *param)//gdb 下 param? 

 

 bool is_real_trans= param- flags   TRANS_IS_REAL_TRANS; 

 

 if (is_real_trans   param- log_pos) 

 { 

 const char *binlog_name= param- log_file; 

 return repl_semisync.commitTrx(binlog_name, param- log_pos); 

 } 

 return 0; 

}

ol start= 1 >

int ReplSemiSyncMaster::commitTrx(const char* trx_wait_binlog_name, 

 my_off_t trx_wait_binlog_pos) 

 // 自旋鎖,下面的代碼是線性執行。 

 mysql_mutex_lock(LOCK_binlog_); 

 if (active_tranxs_ != NULL   trx_wait_binlog_name){ 

 entry=active_tranxs_- find_active_tranx_node(trx_wait_binlog_name, 

 trx_wait_binlog_pos); 

 if (entry) 

 thd_cond=  entry- cond; 

 } 

 // 進入信號了,為后面發起信號量的等待動作做準備,每個正在進行提交的事務都對應一個初始化的信號量 thd_cond 

 THD_ENTER_COND(NULL, thd_cond,  LOCK_binlog_, 

   stage_waiting_for_semi_sync_ack_from_slave, 

   old_stage); 

 if (getMasterEnabled()   trx_wait_binlog_name){ 

 set_timespec(start_ts, 0);// 

 if (!getMasterEnabled() || !is_on()) 

 goto l_end; 

 // 計算等待 ACK 的截止時間。按照當前時間加上半同步等待的超時時間,這個時間回在發起信號量等待的時候用的  

 //rpl_semi_sync_master_timeout 

 abstime.tv_sec = start_ts.tv_sec + wait_timeout_ / TIME_THOUSAND; 

 abstime.tv_nsec = start_ts.tv_nsec +(wait_timeout_ % TIME_THOUSAND) * TIME_MILLION; 

 if (abstime.tv_nsec  = TIME_BILLION){ 

 abstime.tv_sec++; 

 abstime.tv_nsec -= TIME_BILLION; 

 } 

 //state_是 TRUE 表示當前半同步狀態為 on,否則直接進入 l_end。Rpl_semi_sync_master_status 

 //reply_file_name_值的變化,在其他函數中? 

 while (is_on()){ 

 if (reply_file_name_inited_){ 

 // 比較事務所涉及的 binlog 位置跟 reply 的位置,如果 cmp 0,說明此事務的 binlog 已經同步  

 // 到 slave,跳出該循環,進入最后階段 l_end 

 int cmp = ActiveTranx::compare(reply_file_name_, reply_file_pos_, 

 trx_wait_binlog_name, trx_wait_binlog_pos); 

 if (cmp  = 0){ 

 break; 

 } 

 } 

 if (wait_file_name_inited_){ 

 // 比較事務所涉及的 binlog 位置和當前最小需要等待的 binlog 位置。如果 cmp 0,表示調整當前最小需要等待  

 //binlog 的位置。rpl_semi_sync_master_wait_pos_backtraverse++, 即等待位置需要調整的次數,一般不會  

 // 調整  

 int cmp = ActiveTranx::compare(trx_wait_binlog_name, trx_wait_binlog_pos, 

 wait_file_name_, wait_file_pos_); 

 if (cmp  = 0){ 

 strncpy(wait_file_name_, trx_wait_binlog_name, sizeof(wait_file_name_) – 1); 

 wait_file_name_[sizeof(wait_file_name_) – 1]=  \0  

 wait_file_pos_ = trx_wait_binlog_pos; 

 rpl_semi_sync_master_wait_pos_backtraverse++; 

 } 

 

 }else{ 

 // 保存第一次最小需要響應的事務位置  

 strncpy(wait_file_name_, trx_wait_binlog_name, sizeof(wait_file_name_) – 1); 

 wait_file_name_[sizeof(wait_file_name_) – 1]=  \0  

 wait_file_pos_ = trx_wait_binlog_pos; 

 wait_file_name_inited_ = true; 

 } 

 // 如果 salve 個數是 0 了,則將半同步關閉,退出循環  

 if (abort_loop   rpl_semi_sync_master_clients == 0   is_on()){ 

 switch_off(); 

 break; 

 } 

 // 正式進入等待 binlog 同步的步驟,將 rpl_semi_sync_master_wait_sessions+1,表明  

 // 有多少要提交的事務線程在等待(這個值是否能夠代表實際等待事務的線程數量,值得懷疑,因為該函數  

 // 開始位置有 lock,沒有 unlock 前,其他線程也進不到這一步,沒辦法執行 ++) 

 // 然后發起等待信號,進入信號等待后,只有 2 種情況可以退出等待。1 是被其他線程喚醒(binlog dump) 

 // 2 是等待超時時間。如果是被喚醒則返回值是 0,否則是其他值  

 rpl_semi_sync_master_wait_sessions++; 

 entry- n_waiters++; 

 // 發起信號等待,然后根據返回結果做相應計數:上面是循環體里面的所有內容,接下來我們看退出循環后的操作。特別提一下,喚醒該線程的 dump 線程,當 dump 線程收到相應 binlog 位置的 ack 之后,會將其喚醒。 

 wait_result= mysql_cond_timedwait(entry- cond,  LOCK_binlog_,  abstime); 

 entry- n_waiters–; 

 rpl_semi_sync_master_wait_sessions–; 

 if (wait_result != 0){ 

 // 等待超時,關閉半同步  

 rpl_semi_sync_master_wait_timeouts++; 

 switch_off(); 

 }else{ 

 wait_time = getWaitTime(start_ts); 

 if (wait_time   0){ 

 // 表明時鐘錯誤,可能是做了時間調整  

 rpl_semi_sync_master_timefunc_fails++; 

 }else{ 

 // 將等待事件與該等待計入總數  

 rpl_semi_sync_master_trx_wait_num++; 

 rpl_semi_sync_master_trx_wait_time += wait_time; 

 } 

 } 

 }//end while 

l_end: 

 /* Update the status counter. */ 

 if (is_on()) 

 rpl_semi_sync_master_yes_transactions++; 

 else 

 rpl_semi_sync_master_no_transactions++; 

 

 } 

 /* Last waiter removes the TranxNode */ 

 if (trx_wait_binlog_name   active_tranxs_ 

   entry   entry- n_waiters == 0) 

 active_tranxs_- clear_active_tranx_nodes(trx_wait_binlog_name, 

 trx_wait_binlog_pos); 

 THD_EXIT_COND(NULL,   old_stage); 

 

}  

3、流程總結

1)在 commit 函數中,首先需要加一個自旋鎖 LOCK_binlog_,主要動作都在這個鎖內執行。

2)進入信號,為后面發起信號量的等待動作做準備

3)計算 binlog 等待 ACK 的截止時間。從此時開始 + 半同步等待的超時時間 rpl_semi_sync_master_timeout(默認是 10s)

4)需要在半同步狀態下進入下面操作,否則進入 l_end。半同步狀態的判斷是 state_,和 Rpl_semi_sync_master_status 是什么關系?

5)第一次進來:保存最小需要響應的事務位置 wait_file_name_、wait_file_pos_,并將 wait_file_name_inited_置成 TRUE

6)最大響應位置 reply_file_name_、reply_file_pos_在 binlog dump 線程修改,和當前 binlog(已經 flush 的?)的位置比較。若當前 binlog 位置比 reply 的小,表示次事務的 binlog 已經到 slave 了,跳出循環,進入最后階段 l_end

7)非第一次進來:比較事務涉及的 binlog 位置和當前最小需要等待的 binlog 位置。如果比 wai_file_name 的小,需要將最小需要等待的位置調整到當前位置。rpl_semi_sync_master_wait_pos_backtraverse++,即最小等待位置需要調整的次數。一般不會調整。

8)第一次進來:需要保存最小需要等待響應的位置為當前位置

9)接著,需要判斷 slave 個數和半同步是否正常。不正常則退出循環,將半同步關閉

10)正式進入等待 binlog 同步的步驟:

       rpl_semi_sync_master_wait_sessions+1:表示有多少提交的事務線程正在等待

        發起信號等待:mysql_cond_timedwait:只有 2 中情況可以退出等待:1 是被其他線程 binlog dump 喚醒,2 是等待超時。

        特別提一下,喚醒該線程的 dump 線程,當 dump 線程收到相應 binlog 位置的 ack 之后,會將其喚醒。

        等待超時:將半同步關閉

        接收到 slave ACK,被 binlog dump 線程喚醒:修改對應變量

11)將 after_flush 步驟插入 active_trans 的 node 刪掉

12)直到最后一步才釋放鎖,因此該函數是整個實例串行的。同時中間有個信號等待的動作。如果數據庫并發量很大,而此時主從異常,一旦超時時間設置過大,則可能出現其他用戶線程阻塞在 lock() 函數上,杜塞時間越長,累積的線程越多,容易引發雪崩,所以超時時間設置需謹慎,并非隨意設置。

以上是“MySQL 半同步復制的示例分析”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注丸趣 TV 行業資訊頻道!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-07-27發表,共計4982字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 南阳市| 罗平县| 固镇县| 顺义区| 铜陵市| 马关县| 大石桥市| 阳信县| 新宁县| 阜南县| 土默特右旗| 平罗县| 南雄市| 上饶县| 肃北| 闽清县| 古浪县| 洪泽县| 太原市| 英德市| 新河县| 长沙县| 呈贡县| 包头市| 信阳市| 开远市| 芒康县| 维西| 肥乡县| 壶关县| 太康县| 响水县| 郎溪县| 灯塔市| 西丰县| 荃湾区| 凤冈县| 夏邑县| 清水河县| 宜良县| 鸡东县|