最近遇到一個(gè)奇葩的BUG。版本5.7.14,明明主從延遲巨大,但是SBM卻顯示為0,從庫(kù)服務(wù)器時(shí)間沒(méi)有改動(dòng)過(guò)。


翻了一下BUG,查到如下:
https://bugs.mysql.com/bug.php?id=84415
這個(gè)BUG在5.7.22修復(fù)。從BUG的描述中我們也能看到這是其實(shí)是一個(gè)較為嚴(yán)重的BUG。因?yàn)楹芏嗟谋O(jiān)控軟件和高可用都以這個(gè)值為參考值,如果使用低版本的MTS需要注意了。本來(lái)想好好分析下原因,但是發(fā)現(xiàn)主從部分忘了很多,很明顯不可能又去看流程,這個(gè)其實(shí)也在所難免,畢竟即便是自己擼的代碼時(shí)間久了都會(huì)忘記,因此注釋和筆記變得尤為重要。其次修復(fù)一個(gè)較為復(fù)雜的BUG還是比較難的,首先你要知道代碼在描述什么,是什么意思,它的上下文是什么,這就可能直接導(dǎo)致你需要去熟悉某一個(gè)模塊,這也直接反應(yīng)出你對(duì)某個(gè)功能模塊的熟悉程度。
于是我看了下以前的筆記和注釋,勉強(qiáng)記錄如下,
sql線程分發(fā)主要流程:
讀取event->執(zhí)行檢查點(diǎn)(GAQ出隊(duì))->計(jì)算last_master_timestamp->分發(fā)給worker( GAQ入隊(duì) 遇到堵塞)
主要問(wèn)題可能協(xié)調(diào)線程如果在計(jì)算last_master_timestamp的時(shí)候GAP隊(duì)列為空導(dǎo)致計(jì)算計(jì)算延遲異常,而這個(gè)隨后分配的時(shí)候協(xié)調(diào)線程遇到了堵塞導(dǎo)致last_master_timestamp不能更新。因此修改GAQ隊(duì)列為空的情況,轉(zhuǎn)換為直接從sql線程的分配的事務(wù)上獲取延遲。
- mts_checkpoint_routine函數(shù)更改
本函數(shù)主要處理檢查點(diǎn),并且使用lwm的信息填充主從計(jì)算的last_master_timestamp
//如果GAP隊(duì)列為空,會(huì)更新rli->last_master_timestamp == 0
- rli->reset_notified_checkpoint(cnt, rli->gaq->lwm.ts, need_data_lock);
+ ts= rli->gaq->empty()
+ ? 0
+ : reinterpret_cast<Slave_job_group*>(rli->gaq->head_queue())->ts;
+ rli->reset_notified_checkpoint(cnt, ts, need_data_lock, true);
- exec_relay_log_event函數(shù)更改
下面就是取SQL協(xié)調(diào)線程的計(jì)算last_master_timestamp的修改exec_relay_log_event函數(shù)計(jì)算延遲的修改,在分發(fā)函數(shù)apply_event_and_update_pos之前
//如果rli->last_master_timestamp == 0,則說(shuō)明GAP隊(duì)列為空,這里做更改
- if (!(rli->is_parallel_exec() ||
- ev->is_artificial_event() || ev->is_relay_log_event() ||
+ if ((!rli->is_parallel_exec() || rli->last_master_timestamp == 0) && //如果不為MTS或者M(jìn)TS為的last master timestamp為0
+ !(ev->is_artificial_event() || ev->is_relay_log_event() ||
(ev->common_header->when.tv_sec == 0) ||
ev->get_type_code() == binary_log::FORMAT_DESCRIPTION_EVENT ||
ev->server_id == 0))
因此可能監(jiān)控的時(shí)候我們還需要對(duì)執(zhí)行的position或者GTID進(jìn)行監(jiān)控,不要完全相信SBM這個(gè)值。