主頁(yè) > 知識(shí)庫(kù) > MySQL 8.0 redo log的深入解析

MySQL 8.0 redo log的深入解析

熱門(mén)標(biāo)簽:怎樣在地圖標(biāo)注銷(xiāo)售區(qū)域 曲靖移動(dòng)外呼系統(tǒng)公司 地圖標(biāo)注費(fèi)用是多少 啥是企業(yè)400電話辦理 南昌三維地圖標(biāo)注 武漢網(wǎng)絡(luò)外呼系統(tǒng)服務(wù)商 外呼系統(tǒng)打電話上限是多少 百應(yīng)電話機(jī)器人優(yōu)勢(shì) 電話外呼系統(tǒng)改號(hào)

前言

最開(kāi)始了解mysql實(shí)現(xiàn)的時(shí)候,總聽(tīng)到redo log, WAL(write-ahead logging),undo log這些關(guān)鍵詞,了解到redo log主要是用于實(shí)現(xiàn)事務(wù)的持久化的。為了進(jìn)一步了解redo log,看了下相關(guān)代碼(源碼版本: mysql 8.0.12),這里簡(jiǎn)單總結(jié)下,主要介紹redo log是如何產(chǎn)生,如何落盤(pán),以及最終通知用戶(hù)的。

redo log的產(chǎn)生

讀寫(xiě)事務(wù)在執(zhí)行的過(guò)程中,會(huì)不斷的產(chǎn)生redo log。申請(qǐng)數(shù)據(jù)頁(yè)、修改數(shù)據(jù)頁(yè)、記錄undo log等,都會(huì)產(chǎn)生redo log。mysql將用戶(hù)事務(wù)拆分成一個(gè)個(gè)mtr(mini transaction),redo log最初產(chǎn)生時(shí)就是被記錄到mtr中的,并伴隨著mtr的提交而提交,最終落到硬盤(pán)上。

redo log 的提交

mtr在提交時(shí),會(huì)將mtr中的redo log寫(xiě)到系統(tǒng)變量log_sys的log buffer中。mysql8.0一個(gè)新特性就是redo log提交的無(wú)鎖化。在8.0以前,各個(gè)用戶(hù)線程都是通過(guò)互斥量競(jìng)爭(zhēng),串行的寫(xiě)log buffer,因此能保證lsn的順序無(wú)間隔增長(zhǎng)。8.0時(shí)用戶(hù)線程可以并發(fā)寫(xiě)log buffer,如果某個(gè)用戶(hù)線程寫(xiě)log buffer成功后,就將自己寫(xiě)的lsn以前的log buffer刷盤(pán),則有可能導(dǎo)致其他用戶(hù)線程寫(xiě)log buffer還沒(méi)完成就被刷盤(pán)。

為了解決這個(gè)問(wèn)題,mysql 8.0引入了Link_buf這個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)避免log buffer的空洞。Link_buf實(shí)際是一個(gè)定長(zhǎng)數(shù)組,像滑動(dòng)窗口一樣跟蹤log buffer一段區(qū)間的寫(xiě)入情況,隨著log buffer中寫(xiě)入連續(xù)redo log不斷向前推進(jìn)。

Link_buf的數(shù)據(jù)結(jié)構(gòu)如圖:

當(dāng)用戶(hù)在log buffer的start_lsn-end_lsn間寫(xiě)下redo log時(shí),會(huì)標(biāo)記Link_buf相應(yīng)的位置,即將m_link[start_lsn%m_capacity]賦值為為end_lsn-start_lsn。

redo log記錄到log buffer的過(guò)程如下:

1.首先,各用戶(hù)線程寫(xiě)redo log時(shí),先根據(jù)redo log長(zhǎng)度,向系統(tǒng)全局原子變量log_sys.sn獲取本次redo log日志的start_lsn, end_lsn。原子變量sn能保證各線程獲得的start_lsn-end_lsn區(qū)間連續(xù)無(wú)空洞;

2.用戶(hù)線程申請(qǐng)到start_lsn-end_lsn區(qū)間后,需要先等待到Link_buf推進(jìn)到自己可以使用的位置。

如圖所示,start_lsn0-end_lsn0,start_lsn2-end_lsn2, start_lsn3-end_lsn3為三個(gè)用戶(hù)線程新申請(qǐng)的lsn區(qū)間;start_lsn1-end_lsn1對(duì)應(yīng)的區(qū)間已經(jīng)標(biāo)記到link_buf上;start_lsn3-end_lsn3距離tail太遠(yuǎn),需要等待link_buf推進(jìn)才能使用;

3.寫(xiě)入log buffer后,再將start_lsn->end_lsn的范圍標(biāo)記到link_buf(注意:因?yàn)橹辉趕tart_lsn%capacity的位置標(biāo)記link_buf,所以即使end_lsn超過(guò)(m_tail, m_tail+m_capacity)也不影響);

4.用戶(hù)線程提交事務(wù)時(shí)設(shè)置事件log_sys.writer_event,觸發(fā)log_writer線程將日志從redo log buffer寫(xiě)到系統(tǒng)緩存(log_writer線程自己也會(huì)輪詢(xún)link_buf判斷是否寫(xiě)入了新的日志);

5.log_writer線程推進(jìn)m_tail,并將m_tail前的log buffer落盤(pán)。

redo log 的落盤(pán)及通知

前面簡(jiǎn)述了redo log是如何提交的,在redo log提交以及落盤(pán)時(shí),涉及多個(gè)線程,他們的關(guān)系如下:

用戶(hù)線程在讀寫(xiě)事務(wù)提交時(shí),會(huì)產(chǎn)生一些redo log,并隨著mtr提交而記錄到redo log buffer中,隨后用戶(hù)線程嘗試設(shè)置writer_event觸發(fā)log_writer線程寫(xiě)日志,并監(jiān)聽(tīng)屬于自己的flush_events[i]事件;

log_writer線程推進(jìn)Link_buf.m_tail,將最大連續(xù)lsn前的redo log寫(xiě)入系統(tǒng)緩存,并設(shè)置flusher_event觸發(fā)log_flusher線程;

log_flusher線程將已寫(xiě)入系統(tǒng)緩存的日志刷盤(pán),并設(shè)置flush_notifier_event觸發(fā)log_flush_notifier線程通知用戶(hù);

log_flush_notifier根據(jù)已刷盤(pán)的lsn換算出需要觸發(fā)的事件,通知用戶(hù)線程。

具體實(shí)現(xiàn)時(shí),通過(guò)log_sys中的幾個(gè)成員變量,跟進(jìn)redo log的寫(xiě)入情況。其中l(wèi)og_sys.recent_writtern.m_tail表示log buffer最大連續(xù)范圍;log_sys.write_lsn表示寫(xiě)入到系統(tǒng)緩存的位置;log_sys.flushed_to_disk_lsn表示已落盤(pán)的位置。各標(biāo)記的推進(jìn)過(guò)程如下:

通知用戶(hù)線程

用戶(hù)提交事務(wù)時(shí),會(huì)根據(jù)innodb_flush_log_at_trx_commit參數(shù),調(diào)用log_wait_for_write或log_wait_for_flush,來(lái)等待redo log寫(xiě)入到系統(tǒng)緩存或刷到硬盤(pán)。用戶(hù)線程的通知是通過(guò)log_sys.flush_events事件數(shù)組來(lái)實(shí)現(xiàn)的,為了避免一次通知的flush_events過(guò)多,flush_events會(huì)像桶一樣劃分給不同的用戶(hù)線程:redo log是以一個(gè)個(gè)log block劃分的,假設(shè)log_sys.flush_events數(shù)組長(zhǎng)度為m,則第n個(gè)log block的刷盤(pán),由flush_events[n%m]事件監(jiān)聽(tīng)。當(dāng)log buffer的第L1個(gè)log block到第L2個(gè)log block被刷盤(pán)時(shí),會(huì)設(shè)置L1-L2之間的log block所屬的flush_events,從而redo log在L1-L2之間的用戶(hù)線程都會(huì)收到通知。

總結(jié)

mysql8.0通過(guò)redo log無(wú)鎖化,解決了用戶(hù)線程寫(xiě)redo log時(shí)競(jìng)爭(zhēng)鎖帶來(lái)的性能影響。同時(shí)將redo log寫(xiě)文件、redo log刷盤(pán)從用戶(hù)線程中剝離出來(lái),抽成單獨(dú)的線程,用戶(hù)線程只負(fù)責(zé)將redo log寫(xiě)入到log buffer,不再關(guān)心redo log的落盤(pán)細(xì)節(jié),只需等待log_writer線程或log_flusher線程的通知。

以上就是MySQL 8.0 redo log的深入解析的詳細(xì)內(nèi)容,更多關(guān)于MySQL 8.0 redo log的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

您可能感興趣的文章:
  • MySQL 撤銷(xiāo)日志與重做日志(Undo Log與Redo Log)相關(guān)總結(jié)
  • MySQL系列之redo log、undo log和binlog詳解
  • 詳解MySQL 重做日志(redo log)與回滾日志(undo logo)
  • MySQL中的redo log和undo log日志詳解

標(biāo)簽:荊州 黑河 隨州 滄州 資陽(yáng) 吉林 錦州 甘南

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《MySQL 8.0 redo log的深入解析》,本文關(guān)鍵詞  MySQL,8.0,redo,log,的,深入,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《MySQL 8.0 redo log的深入解析》相關(guān)的同類(lèi)信息!
  • 本頁(yè)收集關(guān)于MySQL 8.0 redo log的深入解析的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章