中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

MySQL半同步復制的示例分析

發布時間:2021-11-01 09:26:17 來源:億速云 閱讀:134 作者:小新 欄目:MySQL數據庫

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


代碼分析

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

  2. {  

  3.   

  4.   bool is_real_trans= param->flags & TRANS_IS_REAL_TRANS;  

  5.   

  6.   if (is_real_trans && param->log_pos)  

  7.   {  

  8.     const char *binlog_name= param->log_file;  

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

  10.   }  

  11.   return 0;  

  12. }

<ol start="1" class="dp-cpp" white-space:normal;margin:0px 0px 1px 45px !important;">

  • 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半同步復制的示例分析”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

明星| 双城市| 炉霍县| 舞钢市| 荔波县| 石河子市| 南开区| 宁晋县| 嘉善县| 抚顺市| 文成县| 康乐县| 安岳县| 海阳市| 高台县| 南城县| 清苑县| 巨野县| 治多县| 宜章县| 平凉市| 巴林右旗| 岳普湖县| 利辛县| 禄丰县| 杂多县| 大安市| 屏山县| 玛曲县| 神木县| 曲麻莱县| 娱乐| 行唐县| 三江| 江津市| 翁牛特旗| 遵化市| 同仁县| 昭平县| 扶沟县| 定襄县|