MySQL半同步複製--after_commit
1、介紹
在分析程式碼前,先介紹binlog中幾個位置關係。
2、程式碼分析
- MYSQL_BIN_LOG::ordered_commit->finish_commit:
- ha_commit_low
- RUN_HOOK(transaction, after_commit, (thd, all))->
- (after_commit)repl_semi_report_commit:commitTrx
- 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;
- }
- 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);
- }
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()函式上,杜塞時間越長,累積的執行緒越多,容易引發雪崩,所以超時時間設定需謹慎,並非隨意設定。
4、參考
http://mp.weixin.qq.com/s?__biz=MzIwNzEzNDkxNQ%3D%3D&idx=1&mid=401148347&scene=21&sn=f3372a773ddf948c5ebe35e77a8e1b3a
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31493717/viewspace-2149124/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MySQL 半同步複製MySql
- MySQL半同步複製MySql
- mysql 5.7半同步複製MySql
- MySQL的半同步複製MySql
- MySQL的非同步複製和半同步複製MySql非同步
- 【MySQL】半同步與增強半同步複製MySql
- MySQL 8 複製(二)——半同步複製MySql
- MySQL主從複製之半同步複製MySql
- Mysql5.7半同步複製MySql
- mysql半同步複製的設定MySql
- MySQL 半同步複製+MMM架構MySql架構
- MySQL半同步複製--after_rollbackMySql
- mysql5.5半同步複製探究MySql
- MySQL主從複製、半同步複製和主主複製MySql
- MySQL5.7主從複製-半同步複製搭建MySql
- MySQL主從複製、半同步複製和主主複製概述MySql
- 半同步複製報錯mysql8.0.25MySql
- mysql5.5.9半同步複製功能部署MySql
- mysql5.5中的半同步複製MySql
- MySQL的主從複製、半同步複製、主主複製詳解MySql
- 配置mysql5.5主從複製、半同步複製、主主複製MySql
- MySQL增強(Loss-less)半同步複製MySql
- mysql線上建立半同步複製的從庫MySql
- MySQL5.5半同步複製實現原理MySql
- MySQL5.7新特性半同步複製之AFTER_SYNC/AFTER_COMMIT的過程分析和總結MySqlMIT
- #MySQL# mysql5.7新特性之半同步複製MySql
- MySQL5.7半同步複製報錯案例分析MySql
- MySQL 5.5 Semi-sync 半同步複製測試MySql
- MySQL 5.5半同步複製的配置與監控MySql
- MySQL(二):主從複製結構、半同步複製、雙主複製結構、利用SSL實現安全的MySQL主從複製MySql
- MySQL 5.5 主從複製非同步、半同步以及注意事項詳解MySql非同步
- MySQL 5.7半同步複製after sync和after commit詳解MySqlMIT
- MySQL 8 複製(一)——非同步複製MySql非同步
- 主從複製、雙主複製及半同步複製、以及基於SSL的複製
- Mysql半同步複製模式說明及配置示例 - 運維小結MySql模式運維
- MySQL中的半同步複製(r11筆記第65天)MySql筆記
- MySQL主從複製之非同步複製MySql非同步
- Mariadb之半同步複製叢集配置