MySQL主從復(fù)制從庫SQL線程源碼分析

MySQL主從復(fù)制通過Binlog進行數(shù)據(jù)傳輸,主庫寫入數(shù)據(jù),生成Binlog,通過dump線程將Binlog發(fā)送給從庫,從庫IO線程接收Binlog并寫入自己的relay log,SQL線程應(yīng)用relay log里的事務(wù)。本文結(jié)合MySQL源碼,分析SQL線程的主要處理過程。

MySQL源碼版本:5.7.19

原文地址:
https://mytecdb.com/blogDetail.php?id=90

1. SQL線程啟動

MySQL從庫在執(zhí)行start slave命令時,在MySQL內(nèi)部依次調(diào)用下面的函數(shù)來啟動IO線程和SQL線程。

  • mysql_execute_command(),sql/sql_parse.cc
  • start_slave_cmd(),sql/rpl_slave.cc
  • start_slave(),sql/rpl_slave.cc
  • start_slave_threads(),sql/rpl_slave.cc
  • start_slave_thread(),sql/rpl_slave.cc

其中SQL線程在 start_slave_thread() 函數(shù)中被創(chuàng)建。

start_slave_threads 函數(shù)在另外一個地方也會被調(diào)用,init_slave()函數(shù),這個函數(shù)是在MySQL啟動時調(diào)用,如果沒有指定skip-slave-start,主從復(fù)制隨著MySQL啟動而自動啟動。

2. SQL線程函數(shù)

MySQL主從復(fù)制SQL線程的線程函數(shù)位于sql/rpl_slave.cc文件中,定義如下:

extern "C" void *handle_slave_sql(void *arg)

(1)創(chuàng)建工作線程
在MySQL 5.7 版本,開啟邏輯并行復(fù)制,SQL線程會創(chuàng)建多個工作線程并發(fā)進行relay log日志的應(yīng)用,源碼中創(chuàng)建工作線程的調(diào)用棧如下:

  • handle_slave_sql()
  • slave_start_workers()
  • slave_start_single_worker()
  • mysql_thread_create()

(2)進入循環(huán)
SQL線程創(chuàng)建完工作線程之后,會進入while循環(huán),直到停止復(fù)制或者SQL線程被kill。

在循環(huán)中的主要函數(shù)調(diào)用關(guān)系如下:

  • handle_slave_sql(),SQL線程主函數(shù)
  • exec_relay_log_event()
  • apply_event_and_update_pos()
  • ev->apply_event(rli);
  • ev->do_apply_event()

exec_relay_log_event 函數(shù)讀取relay log中的event。

apply_event_and_update_pos函數(shù)去應(yīng)用relay log event。在這個函數(shù)里,會將thd的server_id設(shè)置成event的server_id,保證event被應(yīng)用后,生成自己的binlog時,server_id仍然是原始值。

apply_event_and_update_pos函數(shù)中會調(diào)用函數(shù)sql_delay_event(),用于處理延遲復(fù)制,比如使用了CHANGE MASTER TO MASTER_DELAY = X 這樣的語法。

ev->apply_event()函數(shù)是event自己成員函數(shù),這個函數(shù)里面會去判斷event是否可以并行應(yīng)用,如果不可以,就在當前線程(SQL線程)去處理這個event,如果可以并行應(yīng)用,則會返回上一層函數(shù)apply_event_and_update_pos,將event丟進入一個隊列,后續(xù)worker線程會去這個隊列中取出event處理。

3. 工作線程主要邏輯

工作線程的線程函數(shù)為:

extern "C" void *handle_slave_worker(void *arg)

主要調(diào)用關(guān)系如下:

  • handle_slave_worker(),工作線程主函數(shù)
  • slave_worker_exec_job_group()
  • slave_worker_exec_event()
  • ev->do_apply_event_worker(this);
  • ev->do_apply_event()
  • mysql_parse()

工作線程內(nèi)部主要是一個while循環(huán),調(diào)用slave_worker_exec_job_group()函數(shù)執(zhí)行分配給自己的任務(wù)。

在slave_worker_exec_job_group函數(shù)中,拿到event后,調(diào)用下面這個函數(shù)應(yīng)用event:
error= worker->slave_worker_exec_event(ev);

在slave_worker_exec_event函數(shù)中又會調(diào)用event自己的成員函數(shù)來應(yīng)用event:
ret= ev->do_apply_event_worker(this);

在do_apply_event_worker函數(shù)中,調(diào)用不同類型event的do_apply_event()成員函數(shù)。比如Query_log_event這種類型的event。
Query_log_event::do_apply_event()

do_apply_event函數(shù)中最終調(diào)用mysql_parse函數(shù)執(zhí)行SQL語句。

4. 總結(jié)

本文簡單分析了MySQL主從復(fù)制SQL線程的主要處理邏輯,MySQL主從復(fù)制是邏輯復(fù)制,從上面過程來看,SQL線程(包括工作線程)從relay log中拿到event,然后像執(zhí)行一個原始SQL一樣在從庫上重新執(zhí)行一次,相對于物理復(fù)制,這種方式效率并不高,耗費資源,并且容易產(chǎn)生復(fù)制延遲。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容