前幾天看到一道面試題,題目是:事務還沒提交的時候,redo log 能不能被持久化到磁盤呢?
“只有客戶發(fā)展了,才有我們的生存與發(fā)展!”這是創(chuàng)新互聯(lián)的服務宗旨!把網(wǎng)站當作互聯(lián)網(wǎng)產(chǎn)品,產(chǎn)品思維更注重全局思維、需求分析和迭代思維,在網(wǎng)站建設中就是為了建設一個不僅審美在線,而且實用性極高的網(wǎng)站。創(chuàng)新互聯(lián)對成都網(wǎng)站設計、網(wǎng)站制作、外貿(mào)營銷網(wǎng)站建設、網(wǎng)站制作、網(wǎng)站開發(fā)、網(wǎng)頁設計、網(wǎng)站優(yōu)化、網(wǎng)絡推廣、探索永無止境。在學習和了解redo日志前,我就在想,這題目啥玩意???一個開發(fā)崗都考這么細嗎?
后來,學習完redo日志后,發(fā)現(xiàn)這個面試題確實挺有意思的。就是考查你對redo日志的了解到底有多深,是停留在表面的理解呢?還是真的修煉到一定程度了,這個題目真的就可以反映出來。
所以,你的答案是什么呢?(答案在文末)
相信讀完本篇文章,理解redo日志后,就會有你自己的答案了…
1. 什么是日志?按照普通字面意思來理解的話,日志是日記中的一種,多指非個人的,一般是記載每天所做的工作。書面日志如"教學日志",“班級日志”,"工作日志"等…
而我們這里所指的日志,則是程序中的日志。對程序的運行過程進行詳細的記錄;是為了保障系統(tǒng)的正常運行,是在程序出現(xiàn)問題時,方便程序員去查閱日志發(fā)現(xiàn)錯誤的重要手段之一。
1.1 數(shù)據(jù)庫日志在數(shù)據(jù)庫系統(tǒng)中,對數(shù)據(jù)的任何更新操作(如:增加、修改、刪除),都要把相關操作的命令、執(zhí)行時間、數(shù)據(jù)的更新等信息保存下來。這些被保存的信息就是數(shù)據(jù)庫日志。也就是說,數(shù)據(jù)庫日志是數(shù)據(jù)庫系統(tǒng)中所有更新活動的操作序列。
更為重要的是,數(shù)據(jù)庫日志是系統(tǒng)正常運行、保持數(shù)據(jù)一致性的重要手段。
redo log(重做日志)則是數(shù)據(jù)庫日志中的一種。它支持再寫入,恢復提交事務修改的數(shù)據(jù)頁操作,以此來保證數(shù)據(jù)的持久性。
2. 為什么需要redo日志?眾所周知,事務有四種特性:原子性、一致性、隔離性、持久性。
那么事務的四種特性到底是基于什么機制實現(xiàn)的呢?
InnoDB存儲引擎是以頁為單位來管理存儲空間的。在真正訪問頁面之前需要把在磁盤上的頁緩存到內(nèi)存中的Buffer Pool
之后才可以訪問。所有的變更都必須先更新緩沖池
中的數(shù)據(jù),然后緩沖池中的臟頁
會以一定的頻率被刷入磁盤(checkPoint
機制),通過緩沖池來優(yōu)化CPU和磁盤之間的鴻溝,這樣就可以保證整體的性能不會下降太快。
但是,由于checkPoint機制并不是在每次修改數(shù)據(jù)時就將臟頁刷入磁盤,這個時候,就怕數(shù)據(jù)庫宕機,一旦宕機,那么緩沖池中的所有臟頁都會被清除;就會出現(xiàn),我們commit親自提交的事務,數(shù)據(jù)庫竟然沒有改變(表情:大驚失色)!
也就是說,事務的持久性失效了??!
那么如何保證事務的持久性呢?這個時候,redo log就應運而生了。
2.1 redo log 的作用我們只是想讓已經(jīng)提交的事務對數(shù)據(jù)庫中數(shù)據(jù)所做的修改永久生效,即使系統(tǒng)崩潰,在重啟后也能把修改的數(shù)據(jù)寫入數(shù)據(jù)庫中。我們只需要將修改了哪些數(shù)據(jù)記錄一下就好。比如:某個事務將系統(tǒng)表空間中第10號頁面中地址偏移量為100處那個字節(jié)的值1改為2;則只需要記錄:將第0號表空間的10號頁面的地址偏移量為100處的值更新為 2 。
InnoDB引擎的事務采用了WAL技術(Write-Ahead Logging 預寫日志系統(tǒng)),這種技術的思想就是先寫日志,再寫磁盤,只有日志寫入成功,才算事務提交成功,這里的日志就是redo log。當發(fā)生宕機且數(shù)據(jù)未刷到磁盤的時候,可以通過redo log來恢復,保證ACID中的D,這就是redo log的作用。
3. redo日志的好處、特點 3.1 好處順序寫入磁盤
的,也就是使用順序IO,效率比隨機IO快。redo log可以簡單分為以下兩個部分:重做日志的緩沖、重做日志文件。
4.1 重做日志的緩沖 (redo log buffer)在服務器啟動時就向操作系統(tǒng)申請了一大片稱之為redo log buffer的連續(xù)內(nèi)存
空間,翻譯成中文就是redo日志緩沖區(qū)。這片內(nèi)存空間被劃分成若干個連續(xù)的redo log block
。一個redo log block占用512字節(jié)
大小。redo log buffer是屬于內(nèi)存層面,是易丟失的。
參數(shù)設置:innodb_log_buffer_size
redo log buffer 大小,默認16M
,大值是4096M,最小值為1M。
mysql>show variables like '%innodb_log_buffer_size%';
+------------------------+----------+
| Variable_name | Value |
+------------------------+----------+
| innodb_log_buffer_size | 16777216 |
+------------------------+----------+
4.2 重做日志文件(redo log file)redo log file是保存在硬盤中,是持久化的。
4.2 redo log的流轉過程以一個更新事務為例,redo log 流轉過程,如下圖所示:
第1步:先將原始數(shù)據(jù)從磁盤中讀入內(nèi)存中(數(shù)據(jù)庫緩沖池)
第2步:生成一條重做日志并寫入redo log buffer,記錄的是數(shù)據(jù)被修改后的值
第3步:當事務commit時,將redo log buffer中的內(nèi)容刷新到 redo log file,對 redo log file采用追加寫的方式
第4步:定期將內(nèi)存中修改的數(shù)據(jù)刷新到磁盤中
redo log的寫入并不是直接將數(shù)據(jù)寫入磁盤的,InnoDB引擎會在寫redo log的時候先寫將數(shù)據(jù)寫入redo log buffer,之后以一定的頻率
刷入到真正的redo log file中。這里的一定頻率怎么看待呢?這就是我們要說的刷盤策略。
注意:redo log buffer刷盤到redo log file的過程并不是真正的刷到磁盤中去,只是刷入到
文件系統(tǒng)緩存
(page cache)中去(這是現(xiàn)代操作系統(tǒng)為了提高文件寫入效率做的一個優(yōu)化),真正的寫入會交給系統(tǒng)自己來決定(比如page cache足夠大了時)。
那么對于InnoDB來說就存在一個問題,如果交給系統(tǒng)來進行寫入,同樣如果系統(tǒng)宕機,那么數(shù)據(jù)也丟失了(雖然整個系統(tǒng)宕機的概率還是比較小的)。
針對這種情況,InnoDB給出innodb_flush_log_at_trx_commit
參數(shù),該參數(shù)控制 commit 提交事務時,如何將 redo log buffer 中的日志刷新到 redo log file 中。它支持三種策略:
show variables like 'innodb_flush_log_at_trx_commit';
mysql>show variables like 'innodb_flush_log_at_trx_commit';
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| innodb_flush_log_at_trx_commit | 1 |
+--------------------------------+-------+
1 row in set (0.00 sec)
另外,InnoDB存儲引擎有一個后臺線程(master thread),每隔1秒,就會把redo log buffer
中的內(nèi)容寫到文件系統(tǒng)緩存(page cache
),然后調用刷盤操作。
也就是說,一個沒有提交事務的redo log
記錄,也可能會被刷入磁盤。因為在事務執(zhí)行過程中,只要發(fā)生數(shù)據(jù)的更改,redo log記錄是會馬上寫入到redo log buffer
中,這些redo log記錄會被后臺線程
刷盤。所以說,對于上面那個字節(jié)的面試題來說。
相信你們已經(jīng)有答案了。
除了后臺線程每秒1次
的輪詢操作,還有一種情況,當redo log buffer
占用的空間即將達到innodb_log_buffer_size
(這個參數(shù)默認是16M)的一半的時候,也就是redo log buffer的容量達到8M時,后臺線程會主動寫盤(由于這個事務可能并沒有提交,所以這個寫盤動作只是 write 到了文件系統(tǒng)的 page cache,仍然是在內(nèi)存中,并沒有調用 fsync 真正落盤)。
innodb_log_group_home_dir:指定redo log文件所在的路徑,默認值為./
。表示在數(shù)據(jù)庫的數(shù)據(jù)目錄下。
MySQL的默認數(shù)據(jù)目錄(linux):var/lib/mysql
;window下則是C:\ProgramData\MySQL\MySQL Server 8.0\Data
,文件下有兩個名為ib_logfile0
和ib_logfile1
的文件。redo log buffer中的日志默認情況下就是刷新到這兩個磁盤文件中。
innodb_log_files_in_group:指明redo log file的個數(shù),命名方式如:ib_logfile0,ib_logfile1…ib_logfilen。默認2個,大100個。
mysql>show variables like 'innodb_log_files_in_group';
+---------------------------+-------+
| Variable_name | Value |
+---------------------------+-------+
| innodb_log_files_in_group | 2 |
+---------------------------+-------+
innodb_flush_log_at_trx_commit:控制 redo log 刷新到磁盤的策略,默認為1(前面已經(jīng)介紹過)。
innodb_log_file_size:單個 redo log file文件設置大小,默認值為48M
。大值為512G,注意大值指的是整個 redo log file系列文件之和,即(innodb_log_files_in_group * innodb_log_file_size )不能大于大值512G。
mysql>show variables like 'innodb_log_file_size';
+----------------------+----------+
| Variable_name | Value |
+----------------------+----------+
| innodb_log_file_size | 50331648 |
+----------------------+----------+
從上邊的描述中可以看到,磁盤上的redo
日志文件不只一個,而是可以以一個日志文件組
的形式出現(xiàn)的。這些文件以ib_logfile[數(shù)字]
(數(shù)字
可以是0、1、2…)的形式進行命名,每個的redo日志文件大小都是一樣的。
在將redo日志寫入日志文件組時,是從ib_logfile0
開始寫,如果ib_logfile0
寫滿了,就接著ib_logfile1
寫。同理,ib_logfile1
寫滿了就去寫ib_logfile2
,依此類推。如果寫到最后一個文件該咋辦?那就重新轉到ib_logfile0
繼續(xù)寫,所以整個過程如下圖所示:
總共的redo log file的大小其實就是:innodb_log_file_size × innodb_log_files_in_group
(即單個文件大小 * 文件個數(shù))。
有人可能會問,ib_logfile0都已經(jīng)寫完了,怎么最后還可以重新轉到ib_logfile0繼續(xù)寫呢?那不就把之前的數(shù)據(jù)給覆蓋了嗎?
對于這個問題,InnoDB的設計者早就想到了,并提出了checkPoint的概念。
6.2.1 checkpoint機制在整個日志文件組中還有兩個重要的屬性,分別是write pos、checkpoint。
write pos
是當前記錄的位置,也就是當前使用到的位置,一邊寫一邊后移checkpoint
是當前要擦除的位置,也是往后推移每次刷盤redo log記錄到日志文件組中,write pos位置就會從0開始后移更新。每次MySQL通過加載日志文件組恢復數(shù)據(jù)時(也就是通過redo log恢復數(shù)據(jù)庫的數(shù)據(jù)),則會清空加載過的redo log記錄(已經(jīng)恢復的數(shù)據(jù)),并把 checkpoint后移更新。write pos和checkpoint之間的還空著的部分可以用來寫入新的redo log記錄。
如果 write pos 追上 checkpoint ,表示日志文件組滿了,這時候不能再寫入新的 redo log記錄,MySQL 得停下來,清空一些記錄,把 checkpoint 推進一下。
7. 總結本文講解了redo日志的出現(xiàn)解決了事務的持久性的問題;以及redo日志的好處和它的特點,還分析了redo日志的組成:redo log buffer 和redo log file,并且介紹了它們各自的職責以及相應的作用。
還有比較重要的一點:redo日志的刷盤策略,這對我們之后的數(shù)據(jù)庫調優(yōu)有一定的幫助和經(jīng)驗。
以及最后redo日志在文件中到底是如何存儲的,它的格式、它的運行機制等。
InnoDB的更新操作采用的是Write Ahead Log(預先日志持久化)策略,即先寫日志,再寫入磁盤。重點掌握redo的作用、組成和刷盤策略等。
面試答案:答案是:事務還沒有提交的時候,redo log 是有可能被持久化到磁盤的。
redolog 的具體落盤操作是這樣的:在事務運行的過程中,MySQL 會先把日志寫到 redolog buffer 中,等到事務真正提交的時候,再統(tǒng)一把 redolog buffer 中的數(shù)據(jù)寫到 redo log 文件中。不過這個從 redolog buffer 寫到 redo log 文件中的操作也就是 write 并不就是落盤操作了,這里僅僅是把 redolog 寫到了文件系統(tǒng)的 page cache 上,最后還需要執(zhí)行 fsync (同步)才能夠實現(xiàn)真正的落盤。
InnoDB 有一個后臺線程,每隔 1 秒輪詢一次,具體的操作是這樣的:調用 write 將 redolog buffer 中的日志寫到文件系統(tǒng)的 page cache,然后調用 fsync 持久化到磁盤。而在事務執(zhí)行中間過程的 redo log 都是直接寫在 redolog buffer 中的,也就是說,一個沒有提交的事務的 redo log,也是有可能會被后臺線程一起持久化到磁盤的。
另外,除了后臺線程每秒一次的輪詢操作外,還有兩種場景會讓一個沒有提交的事務的 redo log 寫盤:
innodb_flush_log_at_trx_commit 設置是 1,這樣并行的某個事務提交的時候,就會順帶將這個事務的 redolog buffer 持久化到磁盤
舉個例子,假設事務 A 執(zhí)行到一半,已經(jīng)寫了一些 redo log 到 redo log buffer 中,這時候有另外一個事務 B 提交,按照 innodb_flush_log_at_trx_commit = 1 的邏輯,事務 B 要把 redolog buffer 里的日志全部持久化到磁盤,這時候,就會帶上事務 A 在 redolog buffer 里的日志一起持久化到磁盤
redo log buffer 占用的空間達到 redo log buffer 大?。ㄓ蓞?shù) innodb_log_buffer_size 控制,默認是 48MB)一半的時候,后臺線程會主動寫盤。不過由于這個事務并沒有提交,所以這個寫盤動作只是 write 到了文件系統(tǒng)的 page cache,仍然是在內(nèi)存中,并沒有調用 fsync 真正落盤。
具體參考:https://zhuanlan.zhihu.com/p/456411101
好了,以上就是本篇文章的全部內(nèi)容,如果對你有所收獲或者啟發(fā)。希望能點贊+收藏支持一下!
我是胡亦,一名熱愛分享技術干貨的博主。
我們下次再見!!🙋?♂?🙋?♂?
你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
文章標題:一文搞懂MySQL之redo日志(含字節(jié)面試題)-創(chuàng)新互聯(lián)
轉載來源:http://aaarwkj.com/article16/iejgg.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供App開發(fā)、品牌網(wǎng)站設計、Google、網(wǎng)站導航、小程序開發(fā)、網(wǎng)站收錄
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)