国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

MySQL層事務(wù)提交的流程

發(fā)布時(shí)間:2021-09-14 18:07 來(lái)源:億速云 閱讀:0 作者:chen 欄目: Mysql 歡迎投稿:712375056

本篇內容主要講解“層事務(wù)提交的流程”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強。下面就讓小編來(lái)帶大家學(xué)習“MySQL層事務(wù)提交的流程”吧!

本節將來(lái)解釋一下MySQL層詳細的提交流程,但是由于能力有限,這里不可能包含全部的步驟,只是包含了一些重要的并且我學(xué)習過(guò)的步驟。我們首先需要來(lái)假設參數設置,因為某些參數的設置會(huì )直接影響到提交流程,我們也會(huì )逐一解釋這些參數的含義。本節介紹的大部分內容都集中在函數MYSQL_BIN_LOG::prepare和MYSQL_BIN_LOG::ordered_commit之中。

一、參數設置

本部分假定參數設置為:

  • binlog_group_commit_sync_delay:0

  • binlog_group_commit_sync_no_delay_count:0

  • binlog_order_commits:ON

  • sync_binlog:1

  • binlog_transaction_dependency_tracking:COMMIT_ORDER

關(guān)于參數binlog_transaction_dependency_tracking需要重點(diǎn)說(shuō)明一下。我們知道Innodb的行鎖是在語(yǔ)句運行期間就已經(jīng)獲取,因此如果多個(gè)事務(wù)同時(shí)進(jìn)入了提交流程(prepare階段),在Innodb層提交釋放Innodb行鎖資源之前各個(gè)事務(wù)之間肯定是沒(méi)有行沖突的,因此可以在從庫端并行執行。在基于COMMIT_ORDER 的并行復制中,last commit和seq number正是基于這種思想生成的,如果last commit相同則視為可以在從庫并行回放,在19節我們將解釋從庫判定并行回放的規則。而在基于WRITESET的并行復制中,last commit將會(huì )在WRITESET的影響下繼續降低,來(lái)使從庫獲得更好的并行回放效果,但是它也是COMMIT_ORDER為基礎的,這個(gè)下一節將討論。我們這節只討論基于COMMIT_ORDER 的并行復制中last commit和seq number的生成方式。

而sync_binlog參數則有兩個(gè)功能:

  • sync_binlog=0:binary log不sync刷盤(pán),依賴(lài)于OS刷盤(pán)機制。同時(shí)會(huì )在flush階段后通知DUMP線(xiàn)程發(fā)送Event。

  • sync_binlog=1:binary log每次sync隊列形成后都進(jìn)行sync刷盤(pán),約等于每次group commit進(jìn)行刷盤(pán)。同時(shí)會(huì )在sync階段后通知DUMP線(xiàn)程發(fā)送Event。注意sync_binlog非1的設置可能導致從庫比主庫多事務(wù)。

  • sync_binlog>1:binary log將在指定次sync隊列形成后進(jìn)行sync刷盤(pán),約等于指定次group commit后刷盤(pán)。同時(shí)會(huì )在flush階段后通知DUMP線(xiàn)程發(fā)送Event。

二、總體流程圖

這里我們先展示整個(gè)流程,如下(圖15-1,高清原圖包含在文末原圖中):


三、步驟解析第一階段(圖中藍色部分)

注意:在第1步之前會(huì )有一個(gè)獲取MDL_key::COMMIT鎖的操作,因此FTWRL將會(huì )堵塞‘commit’操作,堵塞狀態(tài)為‘Waiting for commit lock’,這個(gè)可以參考FTWRL調用的函數make_global_read_lock_block_commit。

(1.)  binlog準備。將上一次COMMIT隊列中最大的seq number寫(xiě)入到本次事務(wù)的last_commit中??蓞⒖糱inlog_prepare函數。

(2.)  Innodb準備。更改事務(wù)的狀態(tài)為準備并且將事務(wù)的狀態(tài)和XID寫(xiě)入到Undo中??蓞⒖紅rx_prepare函數。

(3.)  XID_EVENT生成并且寫(xiě)到binlog cache中。在第10節中我們說(shuō)過(guò)實(shí)際上XID來(lái)自于query_id,早就生成了,這里只是生成Event而已??蓞⒖糓YSQL_BIN_LOG::commit函數。


四、步驟解析第二階段(圖中粉色部分)

(4.)  形成FLUSH隊列。這一步正在不斷的有事務(wù)加入到這個(gè)FLUSH隊列。第一個(gè)進(jìn)入FLUSH隊列的為本階段的leader,非leader線(xiàn)程將會(huì )堵塞,直到COMMIT階段后由leader線(xiàn)程的喚醒。

(5.)  獲取LOCK log 鎖。

(6.)  這一步就是將FLUSH階段的隊列取出來(lái)準備進(jìn)行處理。也就是這個(gè)時(shí)候本FLUSH隊列就不能在更改了??蓞⒖約tage_manager.fetch_queue_for函數。

(7.)  這里事務(wù)會(huì )進(jìn)行Innodb層的redo持久化,并且會(huì )幫助其他事務(wù)進(jìn)行redo的持久化??梢詤⒖糓YSQL_BIN_LOG::process_flush_stage_queue函數。下面是注釋和一小段代碼:

  /*
    We flush prepared records of transactions to the log of storage
    engine (for example, InnoDB redo log) in a group right before
    flushing them to binary log.
  */
  ha_flush_logs(NULL, true);//做innodb redo持久化

(8.) 生成GTID和seq number,并且連同前面的last commit生成GTID_EVENT,然后直接寫(xiě)入到binary log中。我們注意到這里直接寫(xiě)入到了binary log而沒(méi)有寫(xiě)入到binlog cache,因此GTID_EVENT是事務(wù)的第一個(gè)Event。參考函數binlog_cache_data::flush中下面一段:

trn_ctx->sequence_number= mysql_bin_log.m_dependency_tracker.step(); 
//int64 state +1
...
    if (!error)
      if ((error= mysql_bin_log.write_gtid(thd, this, &writer)))
//生成GTID 寫(xiě)入binary log文件
        thd->commit_error= THD::CE_FLUSH_ERROR;
    if (!error)
      error= mysql_bin_log.write_cache(thd, this, &writer);
//將其他Event寫(xiě)入到binary log文件

而對于seq number和last commit的取值來(lái)講,實(shí)際上在MySQL內部維護著(zhù)一個(gè)全局的結構Transaction_dependency_tracker。其中包含三種可能取值方式,如下 :

  • Commit_order_trx_dependency_tracker

  • Writeset_trx_dependency_tracker

  • Writeset_session_trx_dependency_tracker

到底使用哪一種取值方式,由參數binlog_transaction_dependency_tracking來(lái)決定的。
這里我們先研究參數設置為COMMIT_ORDER 的取值方式,對于WRITESET取值的方式下一節專(zhuān)門(mén)討論。

對于設置為COMMIT_ORDER會(huì )使用Commit_order_trx_dependency_tracker的取值方式,有如下特點(diǎn):

其次seq number和last commit這兩個(gè)值類(lèi)型都為L(cháng)ogical_clock,其中維護了一個(gè)叫做offsets偏移量的值,用來(lái)記錄每次binary log切換時(shí)sequence_number的相對偏移量。因此seq number和last commit在每個(gè)binary log總是重新計數,下面是offset的源碼注釋?zhuān)?/p>

  /*
    Offset is subtracted from the actual "absolute time" value at
    logging a replication event. That is the event holds logical
    timestamps in the "relative" format. They are meaningful only in
    the context of the current binlog.
    The member is updated (incremented) per binary log rotation.
  */
  int64 offset;

下面是我們計算seq number的方式,可以參考Commit_order_trx_dependency_tracker::get_dependency函數。

  sequence_number=
    trn_ctx->sequence_number - m_max_committed_transaction.get_offset(); 
//這里獲取seq number

我們清楚的看到這里有一個(gè)減去offset的操作,這也是為什么我們的seq number和last commit在每個(gè)binary log總是重新計數的原因。

(9.) 這一步就會(huì )將我們的binlog cache里面的所有Event寫(xiě)入到我們的binary log中了。對于一個(gè)事務(wù)來(lái)講,我們這里應該很清楚這里包含的Event有:

  • QUERY_EVENT

  • MAP_EVENT

  • DML EVENT

  • XID_EVENT

注意GTID_EVENT前面已經(jīng)寫(xiě)入到的binary logfile。這里我說(shuō)的寫(xiě)入是調用的Linux的write函數,正常情況下它會(huì )進(jìn)入圖中的OS CACHE中。實(shí)際上這個(gè)時(shí)候可能還沒(méi)有真正寫(xiě)入到磁盤(pán)介質(zhì)中。

重復 7 ~ 9步 把FLUSH隊列中所有的事務(wù)做同樣的處理。

注意:如果sync_binlog != 1 這里將會(huì )喚醒DUMP線(xiàn)程進(jìn)行Event的發(fā)送。

(10.) 這一步還會(huì )判斷binary log是否需要切換,并且設置一個(gè)切換標記。依據就是整個(gè)隊列每個(gè)事務(wù)寫(xiě)入的Event總量加上現有的binary log大小是否超過(guò)了max_binlog_size??蓞⒖糓YSQL_BIN_LOG::process_flush_stage_queue函數,如下部分:

 if (total_bytes > 0 && my_b_tell(&log_file) >= (my_off_t) max_size)
    *rotate_var= true; //標記需要切換

但是注意這里是先將所有的Event寫(xiě)入binary log,然后才進(jìn)行的判斷。因此對于大事務(wù)來(lái)講其Event肯定都包含在同一個(gè)binary log中。

到這里FLUSH階段就結束了。


五、步驟解析第三階段(圖中紫色部分)

(11.) FLUSH隊列加入到SYNC隊列。第一個(gè)進(jìn)入的FLUSH隊列的leader為本階段的leader。其他FLUSH隊列加入SYNC隊列,且其他FLUSH隊列的leader會(huì )被LOCK sync堵塞,直到COMMIT階段后由leader線(xiàn)程的喚醒。

(12.) 釋放LOCK log。

(13.) 獲取LOCK sync。

(14.) 這里根據參數delay的設置來(lái)決定是否等待一段時(shí)間。我們從圖中我們可以看出如果delay的時(shí)間越久那么加入SYNC隊列的時(shí)間就會(huì )越長(cháng),也就可能有更多的FLUSH隊列加入進(jìn)來(lái),那么這個(gè)SYNC隊列的事務(wù)就越多。這不僅會(huì )提高sync效率,并且增大了GROUP COMMIT組成員的數量(因為last commit還沒(méi)有更改,時(shí)間拖得越長(cháng)那么一組事務(wù)中事務(wù)數量就越多),從而提高了從庫MTS的并行效率。但是缺點(diǎn)也很明顯可能導致簡(jiǎn)單的DML語(yǔ)句時(shí)間拖長(cháng),因此不能設置過(guò)大,下面是我簡(jiǎn)書(shū)中的一個(gè)案列就是因為delay參數設置不當引起的,如下:
https://www.jianshu.com/p/bfd4a88307f2

參數delay一共包含兩個(gè)參數如下:

  • binlog_group_commit_sync_delay:通過(guò)人為的設置delay時(shí)長(cháng)來(lái)加大整個(gè)GROUP COMMIT組中事務(wù)數量,并且減少進(jìn)行磁盤(pán)刷盤(pán)sync的次數,但是受到binlog_group_commit_sync_no_delay_count的限制。單位為1/1000000秒,最大值1000000也就是1秒。

  • binlog_group_commit_sync_no_delay_count:在delay的時(shí)間內如果GROUP COMMIT中的事務(wù)數量達到了這個(gè)設置就直接跳出等待,而不需要等待binlog_group_commit_sync_delay的時(shí)長(cháng)。單位是事務(wù)的數量。

(15.) 這一步就是將SYNC階段的隊列取出來(lái)準備進(jìn)行處理。也就是這個(gè)時(shí)候SYNC隊列就不能再更改了。這個(gè)隊列和FLUSH隊列并不一樣,事務(wù)的順序一樣但是數量可能不一樣。

(16.) 根據sync_binlog的設置決定是否刷盤(pán)??梢詤⒖己瘮礛YSQL_BIN_LOG::sync_binlog_file,邏輯也很簡(jiǎn)單。

到這里SYNC階段就結束了。

注意:如果sync_binlog = 1 這里將會(huì )喚醒DUMP線(xiàn)程進(jìn)行Event的發(fā)送。


六、步驟解析第四階段(圖中黃色部分)

(17.) SYNC隊列加入到COMMIT隊列。第一個(gè)進(jìn)入的SYNC隊列的leader為本階段的leader。其他SYNC隊列加入COMMIT隊列,且其他SYNC隊列的leader會(huì )被LOCK commit堵塞,直到COMMIT階段后由leader線(xiàn)程的喚醒。

(18.) 釋放LOCK sync。

(19.) 獲取LOCK commit。

(20.) 根據參數binlog_order_commits的設置來(lái)決定是否按照隊列的順序進(jìn)行Innodb層的提交,如果binlog_order_commits=1 則按照隊列順序提交則事務(wù)的可見(jiàn)順序和提交順序一致。如果binlog_order_commits=0 則下面21步到23步將不會(huì )進(jìn)行,也就是這里不會(huì )進(jìn)行Innodb層的提交。

(21.) 這一步就是將COMMIT階段的隊列取出來(lái)準備進(jìn)行處理。也就是這個(gè)時(shí)候COMMIT隊列就不能在更改了。這個(gè)隊列和FLUSH隊列和SYNC隊列并不一樣,事務(wù)的順序一樣,數量可能不一樣。

注意:如果rpl_semi_sync_master_wait_point參數設置為‘AFTER_SYNC’,這里將會(huì )進(jìn)行ACK確認,可以看到實(shí)際的Innodb層提交操作還沒(méi)有進(jìn)行,等待期間狀態(tài)為‘Waiting for semi-sync ACK from slave’。

(22.) 在Innodb層提交之前必須要更改last_commit了。COMMIT隊列中每個(gè)事務(wù)都會(huì )去更新它,如果大于則更改,小于則不變??蓞⒖糃ommit_order_trx_dependency_tracker::update_max_committed函數,下面是這一小段代碼:

{
  m_max_committed_transaction.set_if_greater(sequence_number);
//如果更大則更改
}

(23.) COMMIT隊列中每個(gè)事務(wù)按照順序進(jìn)行Innodb層的提交??蓞⒖糹nnobase_commit函數。

這一步Innodb層會(huì )做很多動(dòng)作,比如:

  • Readview的更新

  • Undo的狀態(tài)的更新

  • Innodb 鎖資源的釋放

完成這一步,實(shí)際上在Innodb層事務(wù)就可以見(jiàn)了。我曾經(jīng)遇到過(guò)一個(gè)由于leader線(xiàn)程喚醒本組其他線(xiàn)程出現問(wèn)題而導致整個(gè)commit操作hang住,但是在數據中這些事務(wù)的修改已經(jīng)可見(jiàn)的案例。

循環(huán)22~23直到COMMIT隊列處理完。

注意:如果rpl_semi_sync_master_wait_point參數設置為‘AFTER_COMMIT’,這里將會(huì )進(jìn)行ACK確認,可以看到實(shí)際的Innodb層提交操作已經(jīng)完成了,等待期間狀態(tài)為‘Waiting for semi-sync ACK from slave’。

(24.) 釋放LOCK commit。

到這里COMMIT階段就結束了。


七、步驟解析第五階段(圖中綠色部分)

(25.) 這里leader線(xiàn)程會(huì )喚醒所有的組內成員,各自進(jìn)行各自的操作了。

(26.) 每個(gè)事務(wù)成員進(jìn)行binlog cache的重置,清空cache釋放臨時(shí)文件。

(27.) 如果binlog_order_commits設置為0,COMMIT隊列中的每個(gè)事務(wù)就各自進(jìn)行Innodb層提交(不按照binary log中事務(wù)的的順序)。

(28.) 根據前面第10步設置的切換標記,決定是否進(jìn)行binary log切換。

(29.) 如果切換了binary log,則還需要根據expire_logs_days的設置判斷是否進(jìn)行binlog log的清理。


八、總結

  • 整個(gè)過(guò)程我們看到生成last commit和seq number的過(guò)程并沒(méi)有其它的開(kāi)銷(xiāo),但是下一節介紹的基于WRITESET的并行復制就有一定的開(kāi)銷(xiāo)了。

  • 我們需要明白的是FLUSH/SYNC/COMMIT每一個(gè)階段都有一個(gè)相應的隊列,每個(gè)隊列并不一樣。但是其中的事務(wù)順序卻是一樣的,是否能夠在從庫進(jìn)行并行回放完全取決于準備階段獲取的last_commit,這個(gè)我們將在第19節詳細描述。

  • 對于FLUSH/SYNC/COMMIT三個(gè)隊列事務(wù)的數量實(shí)際有這樣關(guān)系,即COMMIT隊列>=SYNC隊列>=FLUSH隊列。如果壓力不大它們三者可能相同且都只包含一個(gè)事務(wù)。

  • 從流程中可以看出基于COMMIT_ORDER 的并行復制如果數據庫壓力不大的情況下可能出現每個(gè)隊列都只有一個(gè)事務(wù)的情況。這種情況就不能在從庫并行回放了,但是下一節我們講的基于WRITESET的并行復制卻可以改變這種情況。

  • 這里我們也更加明顯的看到大事務(wù)的Event會(huì )在提交時(shí)刻一次性的寫(xiě)入到binary log。如果COMMIT隊列中包含了大事務(wù),那么必然堵塞本隊列中的其它事務(wù)提交,后續的提交操作也不能完成。我認為這也是MySQL不適合大事務(wù)的一個(gè)重要原因。

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。

人妻少妇精品中文字幕AV蜜桃| 男人把女人桶爽30分钟| 国产真实野战在线视频| 天堂网WWW在线| 无码专区人妻系列日韩| 亚洲愉拍自拍欧美精品|