本篇內(nèi)容主要講解“從庫的SQL線程和sql_slave_skip_counter參數(shù)分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“從庫的SQL線程和sql_slave_skip_counter參數(shù)分析”吧!
網(wǎng)站的建設(shè)創(chuàng)新互聯(lián)建站專注網(wǎng)站定制,經(jīng)驗(yàn)豐富,不做模板,主營網(wǎng)站定制開發(fā).小程序定制開發(fā),H5頁面制作!給你煥然一新的設(shè)計(jì)體驗(yàn)!已為成都雨棚定制等企業(yè)提供專業(yè)服務(wù)。
handle_slave_sql ->是否開啟了slave_preserve_commit_order和log_slave_updates參數(shù),開啟的話需要設(shè)置提交順序管理器 if (opt_slave_preserve_commit_order && rli->opt_slave_parallel_workers > 0 && opt_bin_log && opt_log_slave_updates) commit_order_mngr= new Commit_order_manager(rli->opt_slave_parallel_workers); //order commit 管理器 rli->set_commit_order_manager(commit_order_mngr); ->如果是MTS則需要啟動worker線程 if (slave_start_workers(rli, rli->opt_slave_parallel_workers, &mts_inited) != 0)//啟動worker線程 { MySQL_cond_broadcast(&rli->start_cond); mysql_mutex_unlock(&rli->run_lock); rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, ER(ER_SLAVE_FATAL_ERROR), "Failed during slave workers initialization"); goto err; ->檢查rep table是否是事務(wù)類型的如果不是則報警告 if (!rli->is_transactional()) //是否是 table或者是file類型是table類型則支持事物 rli->report(WARNING_LEVEL, 0, "If a crash happens this configuration does not guarantee that the relay " "log info will be consistent"); -> 初始化 relay log 的訪問位置 if (rli->init_relay_log_pos(rli->get_group_relay_log_name(), rli->get_group_relay_log_pos(), true/*need_data_lock=true*/, &errmsg, 1 /*look for a description_event*/)) //初始化 relay log 的訪問位置 這個位置比較關(guān)鍵也就是從哪里開始讀取我們的relay log。如果出現(xiàn)錯誤將會導(dǎo)致讀取的relay log錯誤。 因此我們需要保證rep info的安全,如果設(shè)置了recover relay log 那么將會初始化為最新一個relay log的 開始位置,因?yàn)樗械奈磮?zhí)行的binlog event將會從新拉取,老的relay log 已經(jīng)不重要了。后面再說。 -> GTID event沒有辦法使用sql_slave_skip_counter 其具體含義參考: Log_event::do_shall_skip mysql> set global sql_slave_skip_counter=1; ERROR 1858 (HY000): sql_slave_skip_counter can not be set when the server is running with @@GLOBAL.GTID_MODE = ON. Instead, for each transaction that you want to skip, generate an empty transaction with the same GTID as the transaction 進(jìn)入循環(huán) 知道SQL線程被殺死 -> 進(jìn)入狀態(tài)stage_reading_event_from_the_relay_log -> 進(jìn)行一段skip event的判斷和日志輸出 GTID event沒有辦法使用sql_slave_skip_counter 其具體含義參考: Log_event::do_shall_skip mysql> set global sql_slave_skip_counter=1; ERROR 1858 (HY000): sql_slave_skip_counter can not be set when the server is running with @@GLOBAL.GTID_MODE = ON. Instead, for each transaction that you want to skip, generate an empty transaction with the same GTID as the transaction -> exec_relay_log_event 讀取應(yīng)用 一個event的上層接口 ->next_event 讀取下一個Event 完成MTS的檢查點(diǎn) ->獲取開始位置 rli->set_event_start_pos(my_b_tell(cur_log)); ->Log_event::read_log_event ->如果是MTS 是否需要進(jìn)行檢查點(diǎn) 1、是否超過檢查點(diǎn)周期 周期檢查在函數(shù)mts_checkpoint_routine內(nèi)部 set_timespec_nsec(&curr_clock, 0); ulonglong diff= diff_timespec(&curr_clock, &rli->last_clock); if (!force && diff < period) { /* We do not need to execute the checkpoint now because the time elapsed is not enough. */ DBUG_RETURN(FALSE); } 2、是否已經(jīng)GAQ已經(jīng)滿了 bool force= (rli->checkpoint_seqno > (rli->checkpoint_group - 1)); //如果達(dá)到了 GAQ的大小 設(shè)置為force 強(qiáng)制checkpoint ->是否relay log 大小已經(jīng)達(dá)到最大 是否需要relay log切換 但是需要注意如果本事物沒有結(jié)束不能進(jìn)行切換
/* If we have reached the limit of the relay space and we 如果我們達(dá)到 relay_log_space_limit 上限 需要通知IO THREAD進(jìn)行切換 清理空間``` are going to sleep, waiting for more events: 1. If outside a group, SQL thread asks the IO thread to force a rotation so that the SQL thread purges logs next time it processes an event (thus space is freed). 2. If in a group, SQL thread asks the IO thread to ignore the limit and queues yet one more event so that the SQL thread finishes the group and is are able to rotate and purge sometime soon. */ if (rli->log_space_limit && rli->log_space_limit < rli->log_space_total) { /* force rotation if not in an unfinished group */ if (!rli->is_parallel_exec()) { rli->sql_force_rotate_relay= !rli->is_in_group(); //如果不是一組就需要切換 } else { rli->sql_force_rotate_relay= (rli->mts_group_status != Relay_log_info::MTS_IN_GROUP); } /* ask for one more event */ rli->ignore_log_space_limit= true;//是一組 不能切換 } ``` ->如果讀取了當(dāng)前relay log的全部的relay log event, ->如果是當(dāng)前relay log ->空閑狀態(tài)下等待io 線程的喚醒,如果是MTS還需要定期醒來進(jìn)行檢查點(diǎn),如下: ``` if (rli->is_parallel_exec() && (opt_mts_checkpoint_period != 0 || DBUG_EVALUATE_IF("check_slave_debug_group", 1, 0))) { int ret= 0; struct timespec waittime; ulonglong period= static_cast<ulonglong>(opt_mts_checkpoint_period * 1000000ULL); ulong signal_cnt= rli->relay_log.signal_cnt; mysql_mutex_unlock(log_lock); do { /* At this point the coordinator has no job to delegate to workers. However, workers are executing their assigned jobs and as such the checkpoint routine must be periodically invoked. */ (void) mts_checkpoint_routine(rli, period, false, true/*need_data_lock=true*/); // TODO: ALFRANIO ERROR mysql_mutex_lock(log_lock); if (DBUG_EVALUATE_IF("check_slave_debug_group", 1, 0)) period= 10000000ULL; set_timespec_nsec(&waittime, period); ret= rli->relay_log.wait_for_update_relay_log(thd, &waittime); } while ((ret == ETIMEDOUT || ret == ETIME) /* todo:remove */ && signal_cnt == rli->relay_log.signal_cnt && !thd->killed); } else { rli->relay_log.wait_for_update_relay_log(thd, NULL); //等待relay log 更改的信號 SQL THREAD 會等待在這里 } ``` -> 如果不是當(dāng)前relay log 那么 SQL線程應(yīng)用或者分發(fā)完成完成后就可以清理了 并且參數(shù)relay_log_purge需要設(shè)置為1 if (rli->relay_log.purge_first_log (rli, rli->get_group_relay_log_pos() == rli->get_event_relay_log_pos() && !strcmp(rli->get_group_relay_log_name(),rli->get_event_relay_log_name())))//做relay log的清理 -> 如果是單SQL現(xiàn)成 獲取event的時間 這一步 就是獲取計(jì)算延遲的重要因素,但是注意MTS不是在這里實(shí)在檢查點(diǎn)里面 last_master_timestamp ``` rli->last_master_timestamp= ev->common_header->when.tv_sec + //event header 的timestamp (time_t) ev->exec_time; //獲取event的 timestamp作為 計(jì)算last_master_timestamp的基礎(chǔ)數(shù)據(jù) query event才有的執(zhí)行時間 DBUG_ASSERT(rli->last_master_timestamp >= 0); //但是對于MTS來講應(yīng)該注意是最后一個XID EVENT的 時間不是這里設(shè)置的 在mts_checkpoint_routine里面 ``` -> 如果GITD_MODE 且AUTO_POSITION 且是MTS需要由協(xié)調(diào)線程進(jìn)行半事物的恢復(fù) (partial transaction) 構(gòu)造回滾EVENT進(jìn)行恢復(fù),而對已非MTS會在gtid event做回滾。 這種情況可能出現(xiàn)在: - AUTO_POSITION情況下如果重連,會重新發(fā)送已經(jīng)傳輸?shù)腅vent。 - AUTO_POSITION情況下如果從庫異常宕機(jī)重啟,并且recovery_relay_log=0的情況下,會重新發(fā)送已經(jīng)傳輸?shù)腅vent,并且relay log pos不會重置 因此我們前面在IO線程和DUMP線程中已經(jīng)討論了,每次sql線程的啟動都會通過GTID去重新尋找需要拉取的 位置。 coord_handle_partial_binlogged_transaction(rli, ev) -> apply_event_and_update_pos 非MTS 完成 應(yīng)用 MTS完成分發(fā) -> 進(jìn)行skip event操作 -> 維護(hù)skip counter計(jì)數(shù)器 if (reason == Log_event::EVENT_SKIP_COUNT) { --rli->slave_skip_counter;//維護(hù)skip count skip_event= TRUE; } 我們看到slave_skip_counter是以event為單位的,但是對于最后一個event如果跨事務(wù)了 那么整個事物都需要跳過。但是skip在GTID模式下是不能用的。 -> 如果不能跳過的事務(wù) 就需要應(yīng)用了。MTS則完成分發(fā) ->完成延遲應(yīng)用邏輯 sql_delay_event(ev, thd, rli) ->ev->apply_event(rli); 這里單SQL線程應(yīng)用 MTS完成分發(fā),分發(fā)方式參考前面 ->是否是進(jìn)行 MTS recovery if (rli->is_mts_recovery()) 根據(jù) bitmap 設(shè)置進(jìn)行跳過處理 if (rli->is_mts_recovery())//如果是恢復(fù) 這個地方就是前面恢復(fù)掃描出來的位置 { bool skip= bitmap_is_set(&rli->recovery_groups, rli->mts_recovery_index) && (get_mts_execution_mode(::server_id, rli->mts_group_status == Relay_log_info::MTS_IN_GROUP, rli->current_mts_submode->get_type() == MTS_PARALLEL_TYPE_DB_NAME) == EVENT_EXEC_PARALLEL); if (skip) { DBUG_RETURN(0); } else { DBUG_RETURN(do_apply_event(rli)); } }
到此,相信大家對“從庫的SQL線程和sql_slave_skip_counter參數(shù)分析”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
網(wǎng)頁名稱:從庫的SQL線程和sql_slave_skip_counter參數(shù)分析
瀏覽路徑:http://muchs.cn/article2/gjsoic.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站、定制開發(fā)、動態(tài)網(wǎng)站、小程序開發(fā)、標(biāo)簽優(yōu)化、關(guān)鍵詞優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)