本文主要介紹innodb重做日志(重做日志撤銷日志binlog),下面一起看看innodb重做日志(重做日志撤銷日志binlog)相關(guān)資訊。
binlog是mysql服務器層的日志,所有的mysql存儲引擎都支持binlog。binlog可以支持主從復制和數(shù)據(jù)恢復,但對事務的acid特性支持較差。innodb存儲引擎引入了redolog和undolog事務日志,以提高事務場景中的數(shù)據(jù)庫性能。本文將介紹redolog和undolog。
redolog和undologchang測試數(shù)據(jù)插入數(shù)據(jù)庫:
創(chuàng)建表user_info( id int主鍵,name varchar(255));插入到user_info(id,name)值(1 ;ls );查詢語句的執(zhí)行過程如果我們需要查詢id=1的用戶的信息,可以通過下面的sql語句進行查詢:
select * from user_info其中id = 1;這個簡單的查詢語句之后mysql做了什么?如下圖所示,mysql執(zhí)行sql查詢語句的過程包括以下步驟:
連接器:客戶端與mysql服務器建立連接,驗證用戶名、密碼等信息;查詢緩存:如果sql語句是查詢語句,檢查查詢語句是否命中緩存;分析器:分析sql語句的詞法和語法,判斷sql語句的類型和對應的表等信息;優(yōu)化器:優(yōu)化sql語句并選擇適當?shù)乃饕?;?zhí)行器:在對應的mysql引擎上執(zhí)行sql查詢語句,返回查詢結(jié)果;update語句的執(zhí)行過程,如果我們不 t不需要查詢用戶信息,但是想將id=1的記錄中的用戶名更新為zs,我們可以通過下面的sql語句進行更新:
更新用戶信息集名稱= zs 其中id = 1;類似于上面文章中的查詢語句,mysql會先通過connector建立數(shù)據(jù)庫連接,然后通過analyzer、optimizer和executor找到需要更新數(shù)據(jù)的行,然后更新數(shù)據(jù)。
與查詢過程不同,更新過程還涉及changebuffer和兩個重要的日志模塊:binlog和redolog。binlog和changebuffer的角色在上一篇文章中已經(jīng)介紹過了。如上所述,binlog用于主從復制和數(shù)據(jù)恢復,changebuffer用于緩存數(shù)據(jù)庫中數(shù)據(jù)的操作,redolog是本文介紹的主角。
changebuffer技術(shù)對于上面的update語句,如果沒有redolog,innodb引擎會根據(jù)索引找到id=1的用戶記錄,將記錄加載到內(nèi)存中,然后修改內(nèi)存中的數(shù)據(jù)事務,寫回磁盤。如果數(shù)據(jù)庫數(shù)據(jù)更新的頻率很低,那么這種更新對于數(shù)據(jù)庫來說是可以接受的,但是在更新非常頻繁的情況下,大量的離散io會成為數(shù)據(jù)庫的瓶頸,影響數(shù)據(jù)庫的性能。
在頻繁更新的場景下,如何降低磁盤的io,保證事務?這涉及到我們在上一篇文章中介紹的changebuffer技術(shù)。innodb不會立即將數(shù)據(jù)更改操作寫入磁盤,而是將這些操作緩存在changebuffer中的數(shù)據(jù)頁上,數(shù)據(jù)庫會找到合適的機會將操作合并到數(shù)據(jù)庫中。
通過changebuffer技術(shù),我們可以將多個離散的數(shù)據(jù)庫訪問合并成一個數(shù)據(jù)庫訪問,并且用戶 的更新線程不需要實際訪問磁盤,這大大提高了數(shù)據(jù)庫性能。
沃爾科技,然而,我不 t不知道大家有沒有注意到changebuffer有一個很大的問題:如果innodb實例在運行過程中斷電,changebuffer中的緩存就會丟失,從而造成數(shù)據(jù)庫數(shù)據(jù)的不一致,影響數(shù)據(jù)庫事務的原子性和一致性。
保證數(shù)據(jù)庫中事務的原子性和一致性的一般方案是采用wal(預寫日志記錄)技術(shù)。在使用wal的系統(tǒng)中,所有的修改首先被寫入日志,然后應用到系統(tǒng)狀態(tài)。日志通常包含兩部分信息:重做和撤消。
重做日志稱為重做日志。每當有操作時,都會在數(shù)據(jù)發(fā)生變化前將操作寫入redolog,這樣當停電時,系統(tǒng)重啟后還能繼續(xù)運行。undolog稱為undo log,在執(zhí)行中途某些變更無法完成時,可以根據(jù)undo log恢復到變更之間的狀態(tài);wal技術(shù)在mysql 的innodb引擎,所以innodb存儲引擎包含日志的兩個部分:redolog和undolog。
如何保證提交的事務不會丟失?解決這個問題比較簡單。innodb有一個logforceatcommit機制。提交事務時,與該事務相關(guān)的重做日志數(shù)據(jù)(包括提交記錄)必須從日志緩沖區(qū)寫入重做日志文件。只有當事務成功提交時,信號才能發(fā)送到用戶進程。通過這種機制,可以保證即使這個提交事務中的changebuffer有一部分沒有被寫入數(shù)據(jù)文件,也會發(fā)生實例故障,在實例恢復時,可以通過redolog的信息前滾不一致的數(shù)據(jù)。
重做日志和二進制日志的比較重做日志和二進制日志不同。雖然innodb表的很多操作也記錄在binlog中,并且可以實現(xiàn)重做的功能,但是兩者有很大的區(qū)別。
binlog在存儲引擎的上層生成。無論什么存儲引擎,修改數(shù)據(jù)庫時都會生成二進制日志。redolog由innodb引擎層生成,只記錄存儲引擎中表的變化;binlog是記錄數(shù)據(jù)變化的邏輯語句,比如一行數(shù)據(jù)的變化或者這個變化的sql語句。redolog是物理格式的日志,記錄數(shù)據(jù)庫中每個頁面的修改情況;binlog只寫入日志 文件 每次提交事務時在緩存中保存一次(對于非事務性表操作,在每次成功執(zhí)行語句后直接寫入)。重做日志在數(shù)據(jù)準備修改之前寫入緩存中的重做日志,然后修改緩存中的數(shù)據(jù);而且保證了在發(fā)出事務提交指令時,先將磁盤日志寫入緩存中的redolog,完成寫入后才執(zhí)行提交動作;binlog在提交時只寫一次,所以binlog的記錄和提交順序有關(guān),每次提交對應一條記錄。重做日志是對記錄的物理頁面的修改。redolog文件中的同一個事務可能被記錄多次,最后提交的事務記錄將覆蓋所有未提交的事務記錄。例如,在事務t1中,可以在重做日志中記錄四個操作t11、t12、t13和t1,其中t1表示最后一次提交時的日志記錄,因此對應數(shù)據(jù)頁的最終狀態(tài)是對應于t1的操作結(jié)果。而且redolog是并發(fā)寫入的,不同事務之間不同版本的記錄會交替寫入redolog文件。例如,redolog的記錄方法可能如下:t11、t12、t21、t22、t2、t13、t1 *。事務日志記錄物理頁面的情況,是冪等的,所以日志記錄的極其簡潔。冪等性是指多次運算前后狀態(tài)相同。例如,在插入新行并將其刪除后,狀態(tài)保持不變。二進制日志記錄了所有影響數(shù)據(jù)的操作,記錄的內(nèi)容更多。例如,插入一行記錄一次,然后再次刪除該行。
重做日志重做日志由兩部分組成:一部分是內(nèi)存中的日志緩沖區(qū),這部分日志是易變的;第二個是磁盤上的重做日志文件,它是持久的。
從概念上來說,innodb通過forcelogatcommit機制實現(xiàn)了事務的持久化,即當一個事務被提交時,該事務的所有事務日志都必須寫入磁盤上的redolog文件和undolog文件中才能持久化。
為了保證每個日志都能被寫入事務日志文件,每次redolog緩沖區(qū)中的日志被寫入日志文件時,都會調(diào)用操作系統(tǒng)的fsync操作(即fsync系統(tǒng)調(diào)用)。因為mariadb/mysql工作在用戶空間,所以mariadb/mysql的redolog緩沖區(qū)在用戶空間的內(nèi)存中。要寫入磁盤上的重做日志緩沖區(qū),它必須通過操作系統(tǒng)內(nèi)核空間中的操作系統(tǒng)緩存。調(diào)用fsync的作用是將操作系統(tǒng)緩存中的日志刷到磁盤上的redolog文件中。
redolog事務日志的文件名是ib_logfilen,比如ib_logfile0和ib_logfile1。......
redolog將日志從緩存寫入磁盤,如下圖所示:
mysql支持用戶自定義事務提交時如何將日志緩存中的日志刷入磁盤文件。它可以由變量innodb_flush_log_at_trx_commit的值來控制。該變量有三個值:0、1和2,默認值為1。但是,請注意,該變量僅控制在提交事務時是否將日志緩存刷新到磁盤。
當設(shè)置為1時,日志緩存中的日志將在提交事務時寫入操作系統(tǒng)緩存,并將調(diào)用fsync保存到磁盤文件中。這樣即使系統(tǒng)崩潰也不會有數(shù)據(jù)丟失,但是因為每次提交都是寫到磁盤,io的性能很差。當設(shè)置為0時,日志緩存中的日志不會在提交事務時寫入操作系統(tǒng)緩存,而是每秒寫入操作系統(tǒng)緩存,并調(diào)用fsync保存到磁盤文件中。也就是說,設(shè)置為0時,每秒刷新一次寫入磁盤,系統(tǒng)崩潰時會丟失1秒的數(shù)據(jù);設(shè)置為2時,事務只在提交時寫入操作系統(tǒng)緩存,然后每秒調(diào)用fsync將操作系統(tǒng)緩存中的日志持久化到磁盤文件中;有一個變量innodb_flush_log_at_timeout,值為1秒,表示日志記錄的頻率。很多人誤以為是在innodb_flush_log_at_trx_commit的值為0和2時控制1秒的頻率,其實不是。以測試時間設(shè)置頻率。設(shè)置為5和1時,innodb_flush_log_at_trx_commit設(shè)置為0和2時,性能基本不變。這個頻率是怎么控制的?這將在后面的 刷日志到磁盤的規(guī)則 。
保證一致性在主從復制結(jié)構(gòu)中,為了保證事務的持久性和一致性,需要對日志相關(guān)的變量進行如下設(shè)置:
如果啟用了binlog,則設(shè)置sync_binlog=1,即每個事務都同步寫入磁盤。始終設(shè)置innodb _ flush _ log _ at _ trx _ commit = 1,即每個事務都寫入磁盤。上述兩個變量的設(shè)置保證了每次提交事務時,都會寫入二進制日志和事務日志,提交時會刷新到磁盤。
選擇模式1時,因為每個事務都提交到磁盤,所以在大量小事務的場景下,會影響數(shù)據(jù)庫的性能。
redolog日志塊在innodb存儲引擎中,redolog是分塊存儲的,每個塊占512字節(jié),稱為redolog日志塊。日志緩存、系統(tǒng)緩存和磁盤中的重做日志文件以這種存儲在512字節(jié)的塊中。
重做日志記錄數(shù)據(jù)頁的更改。當需要用超過492字節(jié)的重做日志記錄一個數(shù)據(jù)頁的變化時,那么將使用多個重做日志日志塊來記錄該數(shù)據(jù)頁的變化。
關(guān)于redolog日志塊頭的第三部分log_block_first_rec_group,因為有時候一個數(shù)據(jù)頁面生成的日志量超過一個日志塊,所以需要使用多個日志塊來記錄頁面的相關(guān)日志。比如一個數(shù)據(jù)頁生成一個552字節(jié)的日志卷,需要占用兩個日志塊,第一個日志塊占用492字節(jié),第二個日志塊占用60字節(jié),那么對于第二個日志塊,其第一個日志的起始位置是73字節(jié)(60 ^ 12)。如果log_block_first_rec_group的值等于log_block_hdr_data_len,說明這個日志塊中沒有新開始的日志塊,也就是說這個日志塊是用來延續(xù)前面的日志塊的。日志末尾只有一部分:log_block_trl_no,等于塊頭的log_block_hdr_no。
內(nèi)存中的重做日志緩存和磁盤中的重做日志文件由多個日志塊組成,如下圖所示:
重做日志組重做日志組由多個大小相同的重做日志文件組成。組中重做日志文件的數(shù)量由變量innodb_log_files_group決定,默認值為2。也就是說,兩個重做日志文件形成一個重做日志組。這個組是一個邏輯概念,沒有真實的文件來表示它是一個組,但是組的目錄可以用變量innodb_log_group_home_dir來定義,redolog文件會放在這個目錄下(默認在datadir下)。
mysql顯示全局變量,如 innodb _ log % |變量名稱|值|| innodb _ log _ buffer _ size | 16777216 | | innodb _ log _ checksums | on | | innodb _ log _ compressed _ pages | on | | innodb _ log _ file _ size | 50331648 | | innodb _ log _ files _ in _ group | 2 | | innodb _ log _ group _ home _ dir |。/| | innodb _ log _ write _ ahead _ size | 8192 |集合中的7行(0.06秒)root@b48c:/var/lib/mysql# lsl ib *rwr1 mysql root 407 oct 21 09 : 36 ib _ buffer _ poolrwr1 mysql mysql 50331648 oct 26 09 : 00 ib _ log file 0rwr1m ysql mysql根據(jù)目錄,有兩個以ib_logfile開頭的文件,是redolog日志組中的redolog文件,它們的大小完全相同,等于變量innodb_log_file_size定義的值。當innodb_file_per_table未打開時,ibdata1文件是一個共享表空間文件,對應于。打開innodb_file_per_table時的ibd文件。
當innodb將日志緩存中的redolog日志塊刷入redolog文件時,會以額外寫入的形式輪流寫入。也就是說,在第一個重做日志文件(ib_logfile0)的末尾寫入,然后寫入第二個重做日志文件(ib_logfile1),直到寫滿為止。當?shù)诙€重做日志文件已滿時,第一個重做日志文件的一部分將被清空以繼續(xù)寫入。
因為日志緩存中的日志被刷到了redolog文件中,所以在redolog文件中記錄日志的也是redolog日志塊的。redolog文件的大小對innodb的性能有很大的影響。如果設(shè)置得太大,需要很長時間恢復,如果設(shè)置得太小,會導致寫redolog時循環(huán)切換redolog文件。
在每個組的第一個重做日志文件中,前2kb記錄四個特定部分,2kb之后記錄重做日志塊。除了第一個重做日志文件,重做日志日志組中的其他重做日志文件不會記錄2kb,但會為2kb騰出空間。
重做日志文件格式innodb存儲引擎將數(shù)據(jù)存儲在一個頁面中,因此重做日志也基于頁面格式進行記錄。默認情況下,innodb的頁面大小為16kb(由變量innodb_page_size控制),一個頁面可以存儲多個重做日志塊(每個512字節(jié)),重做日志塊記錄數(shù)據(jù)頁面的變化。
重做日志塊的492字節(jié)部分是重做日志內(nèi)容,重做日志內(nèi)容的格式分為四個部分:
redo_log_type:占用1個字節(jié),表示重做日志的日志類型;space:表空間的id。壓縮后,占用的空間可能小于4字節(jié);page_no:表示頁面的偏移量,也是壓縮的;redo_log_body表示每個重做日志的數(shù)據(jù)部分,還原時會調(diào)用相應的函數(shù)進行解析。redolog記錄格式redolog的本質(zhì)是記錄事務對數(shù)據(jù)庫做了哪些更改。innodb 美國設(shè)計師專注于事物為數(shù)據(jù)庫的不改場景定義了多種類型的重做日志,但大多數(shù)類型的重做日志具有以下一般結(jié)構(gòu):
各部分的詳細解釋如下:
類型:此重做日志的類型。在這個版本的mysql 5.7.21中,innodb中有53種不同類型的重做日志,后面會詳細介紹不同類型的重做日志??臻gid:表空間id。頁碼:頁碼。數(shù)據(jù):這個重做日志的具體內(nèi)容。我贏了。;本文不介紹重做日志的更詳細的格式。有興趣的可以自己找文檔。此時我們應該知道,如果我們使用insert語句向數(shù)據(jù)庫中插入一條記錄,那么redolog將記錄指定的值將被設(shè)置在指定空間中指定數(shù)據(jù)頁的指定地址。
當redolog磁盤擦洗策略變量innodb_flush_log_at_trx_commit的值為1時,每次提交事務時,redolog事務日志都會被擦洗到磁盤,但innodb不會只在icommit之后將日志擦洗到磁盤,這只是innodb存儲引擎的規(guī)則之一。有幾種情況會觸發(fā)日志清理:
提交動作發(fā)出時,提交發(fā)出后是否刷日志由變量innodb_flush_log_at_trx_commit控制。每秒刷一次。日志記錄的頻率由變量innodb_flush_log_at_timeout的值決定,默認值為1秒。應該注意,這個日志記錄頻率與提交操作無關(guān)。當日志緩沖區(qū)中一半以上的內(nèi)存已被使用時。當存在檢查點時,檢查點表示當日志在某種程度上被移動到磁盤時日志的lsn位置。dirtydata是在檢查點的緩沖池中未刷到磁盤的臟數(shù)據(jù)。因為數(shù)據(jù)和日志都以頁的形式存在,所以臟頁表示臟數(shù)據(jù)和臟日志。最后一節(jié)介紹了日志被刷到磁盤的時間。不僅日志要刷,臟數(shù)據(jù)頁也要刷。
在innodb中,數(shù)據(jù)清理只有一個規(guī)則:檢查點。但是有幾種情況會觸發(fā)檢查點。在任何情況下,觸發(fā)檢查點后,緩存中的臟數(shù)據(jù)頁和臟日志頁都將被刷到磁盤。
innodb存儲引擎中有兩種檢查點:
sharp checkpoint:重用redolog文件時(比如切換日志文件),將redolog中記錄的臟數(shù)據(jù)全部刷到磁盤上。模糊checkpoint:一次只刷一小部分日志到磁盤,而不是所有臟日志。以下情況會觸發(fā)檢查點:主線程檢查點:由主線程控制,每秒或每10秒刷一定比例的臟頁到磁盤;flush_lru_list檢查點:從mysql5.6開始,可以通過innodb_page_cleaners變量指定負責清理臟頁的pagecleaner線程的數(shù)量,這個線程的目的是保證lru列表有可用的空閑頁;異步/同步刷新檢查點:同步或異步磁盤刷。比如還有很多臟頁沒有刷到磁盤上(有多少,比例控制)。這時候你會選擇同步刷到磁盤,但這種情況很少發(fā)生;如果臟頁不多,可以選擇異步刷到磁盤;如果臟頁少,可以暫時不刷到磁盤;臟頁過多檢查點:當臟頁過多時,檢查點被強制觸發(fā),以確保緩存有足夠的空閑空間。過多的比例由變量innodb_max_dirty_pages_pct控制,mysql 5.6的默認值是75,即當臟頁占緩沖池的75%時,強制將部分臟頁刷到磁盤。因為完成臟頁需要一定的時間,所以每次磁盤刷完之后,都會在redolog中標記檢查點的位置。mysql停止時是否將臟數(shù)據(jù)和臟日志刷到磁盤由變量innodb_fast_shutdown={ 0|1|2}控制,默認值為1,即mysql停止時只進行一部分purge,大部分的刷新操作被忽略(但至少會刷日志),剩下的在mysql下次啟動時刷新,實現(xiàn)fastshutdown。
lsn學習lsn被稱為日志序列號。在innodb存儲引擎中,lsn占用8個字節(jié),lsn的值會隨著日志的寫入而增加。分析lsn可以獲得很多關(guān)鍵信息:
數(shù)據(jù)頁的版本信息。寫入的日志總量可以通過lsn開始編號和結(jié)束編號來計算。檢查站的位置。lsn不僅存在于重做日志中,也存在于數(shù)據(jù)頁中。在每個數(shù)據(jù)頁的頭部,有一個fil_page_lsn,記錄當前頁的最終lsn值。通過比較數(shù)據(jù)頁中的lsn值和重做日志中的lsn值,如果頁中的lsn值小于重做日志中的值,則意味著丟失了一些數(shù)據(jù)。此時可以通過redolog的記錄恢復重做。日志中記錄的lsn值。
重做日志的lsn信息可以通過顯示引擎innodb狀態(tài)來查看。mysql版的顯示結(jié)果只有三條記錄,沒有刷新到的頁面。
mysql顯示引擎innodb狀態(tài)...... log 日志序列號12734454日志刷新達到12734454頁面刷新達到12734454最后一個檢查點為1273 44450掛起日志刷新,0掛起chkp寫入45日志i/o ;完成,0.00日志輸入/輸出 s/秒,其中
日志序列號是當前重做日志中的lsn,通常與緩存中的lsn一致,稱為緩存日志lsn刷新到的日志是磁盤上重做日志文件中的lsn,通常小于日志緩存lsn,稱為磁盤日志lsnpages flushed up是已經(jīng)刷在磁盤數(shù)據(jù)頁上的lsn,稱為磁盤數(shù)據(jù)頁lsn;最后一個檢查站是lsn的最后一個檢查站,這是所謂的lsn檢查站。innodb執(zhí)行修改數(shù)據(jù)庫語句的過程如下:
將redolog寫入redolog緩存,并將redolog中對應的lsn記錄為緩存日志lsn如果目標數(shù)據(jù)頁在緩存中,則修改緩存中的數(shù)據(jù)頁,并將數(shù)據(jù)頁中的lsn記錄為緩存的數(shù)據(jù)頁lsn;當日志刷回磁盤時,在redolog文件中記錄對應的lsn,記為磁盤日志lsn;數(shù)據(jù)頁中的lsn在檢查點臟的時候緩存,記錄為檢查點lsn;;在checkpoint要刷的數(shù)據(jù)頁很多,刷完所有的數(shù)據(jù)頁需要一定的時間。每滑一半的數(shù)據(jù)頁都會記錄當前頁所在的lsn,暫且稱為磁盤數(shù)據(jù)頁lsn。下圖顯示了交易過程中各lsn的變化情況:
12 : 00 : 00.000時間,交易開始。最初,假設(shè)每個lsn是001;12 : 00 : 00.200,執(zhí)行update語句1,更新緩存日志lsn和緩存數(shù)據(jù)頁lsn,分別加1。,改為001;12 : 00 : 00.400,執(zhí)行update語句2,分別更新緩存日志lsn和緩存數(shù)據(jù)頁lsn,加1改為002;12 : 00 : 00.600,執(zhí)行update語句3,分別更新緩存日志lsn和緩存數(shù)據(jù)頁lsn,加1改為003;12 : 00 : 01.000時間,檢查點,將緩存中的日志和數(shù)據(jù)頁刷回磁盤,將磁盤數(shù)據(jù)頁和磁盤日志的lsn更新為003,將檢查點的lsn更新為003;12 : 00 : 01.200,執(zhí)行update語句3,分別更新緩存日志lsn和緩存數(shù)據(jù)頁lsn,加1改為004;12 : 00 : 01.400,事務提交,緩存日志寫入磁盤,磁盤日志lsn更新為004;12 : 00 : 02.000時間,檢查點,將緩存中的日志和數(shù)據(jù)頁刷回磁盤,磁盤數(shù)據(jù)頁lsn更新為004,檢查點lsn更新為004;innodb crashsafe在啟動innodb時總是會恢復,不管它上次是正常關(guān)閉還是異常關(guān)閉。因為redolog記錄的是數(shù)據(jù)頁的物理變化,所以恢復起來比邏輯日志(比如binlog)要快得多。而且innodb本身也做了一定程度的優(yōu)化,讓恢復速度更快。
innodb重啟時,checkpoint代表已經(jīng)完全刷到磁盤上數(shù)據(jù)頁的lsn,所以恢復時只需要恢復從checkpoint開始的日志部分。例如,當數(shù)據(jù)庫的lsn在最后一個檢查點為10000時,事務處于提交狀態(tài)。當數(shù)據(jù)庫啟動時,將檢查磁盤中數(shù)據(jù)頁的lsn。如果數(shù)據(jù)頁的lsn小于日志中的lsn,恢復將從檢查點開始。
還有一種情況,停機前,在檢查點刷盤過程中,數(shù)據(jù)頁的刷盤進度超過了日志頁。此時,當機器停機時,數(shù)據(jù)頁中記錄的lsn將大于日志頁中的記錄,這將在重啟恢復過程中進行檢查。這時候超出日志進度的部分就不會重做,因為這本身就意味著已經(jīng)做了的事情不需要重做。
此外,事務日志是冪等的,因此多次操作后得到相同結(jié)果的行為是它在日志中只記錄一次。二進制日志不是冪等的,所以會記錄很多操作,恢復時會多次執(zhí)行二進制日志中的記錄,速度慢很多。比如一條記錄中id的初始值為2,通過update設(shè)置為3,再設(shè)置為2,那么事務日志中記錄的頁面就不變,根本不需要恢復;二進制文件將記錄兩個更新操作,這兩個操作也將在恢復過程中執(zhí)行,這比事務日志恢復要慢。
redolog相關(guān)變量innodb _ flush _ log _ at _ trx _ commit = { 0 | 1 | 2 }:指定何時將事務日志刷到磁盤;默認值為1;0表示 日志緩沖區(qū) 將同步到 操作系統(tǒng)緩沖區(qū)和每秒和刷從 操作系統(tǒng)緩沖區(qū)和到磁盤日志文件;1表示每個事務提交都將同步日志緩沖區(qū) 致 操作系統(tǒng)緩沖區(qū)和從 操作系統(tǒng)緩沖區(qū)和到磁盤日志文件;2意味著每個事務提交都是同步的日志緩沖區(qū) 致 操作系統(tǒng)緩沖區(qū)和但只有來自 操作系統(tǒng)緩沖區(qū)和到磁盤日志文件;innodb _ log _ buffer _ size:log buffer的大小,默認值為8minnodb_log_file_size:事務日志的大小,默認值為5minnodb_log_files_group =2:事務日志組中事務日志文件的數(shù)量。默認值為2 innodb_log_group_home_dir =。/:事務日志組路徑,當前目錄代表數(shù)據(jù)目錄innodb_mirrored_log_groups =1:指定事務日志組的鏡像組數(shù),但是鏡像功能好像被強制關(guān)閉了,所以只有一個redolog組。這個變量在mysql5.7中已經(jīng)被刪除了,undolog的基本概念有兩個功能:提供回滾和多行版本控制(mvcc)。
當數(shù)據(jù)被修改時,wal技術(shù)不僅記錄重做日志,還記錄相應的撤消日志。如果事務由于某種原因失敗或回滾,可以在這個undolog的幫助下回滾。
undolog和redolog記錄不同的物理日志,它們是邏輯日志??梢哉J為,當記錄被刪除時,相應插入記錄將被記錄在undolog中,反之亦然;當記錄被更新時,它記錄相應的相反的更新記錄。
當執(zhí)行回滾時,可以從undolog中的邏輯記錄讀取相應的內(nèi)容并回滾。有時應用于行版本控制時,也是通過undolog來實現(xiàn)的:當讀取一行時,當被其他事務鎖定時,可以從undolog中分析出該行記錄之前的數(shù)據(jù)是什么,從而提供該行的版本信息,讓用戶實現(xiàn)非鎖定一致讀取。
undolog是以段的形式記錄的,每次撤銷操作在記錄時都占用一個undolog段。
此外,undolog還會產(chǎn)生redolog,因為undolog也需要實現(xiàn)持久保護。
undolog存儲模式innodb存儲引擎采用分段模式管理undo?;貪L段稱為回滾段,每個回滾段有1024個undolog段。
之前的老版本只支持一個回滾段,所以只能記錄1024個undolog段。后來的mysql5.5可以支持128個回滾段,也就是128*1024次撤銷操作,可以通過變量innodb _ undo _ logs(5.6版之前這個變量是innodb_rollback_segments)自定義多少個回滾段。默認值為128。默認情況下,undolog存儲在共享表空間中。
root@b48c:/var/lib/mysql# lsl ib *rwr1 mysql root 407 oct 21 09 : 36 ib _ buffer _ poolrwr1 mysql 50331648 oct 26 09 : 00 ib _ log file 0rwr1m ysql mysql 50331648 oct 20 07 : 24 ib _ log file 1rw每個表的ibd文件。在mysql5.6中,undo的存儲位置也可以由變量innodb_undo_directory定義,默認值為 。 對于datadir。
默認rollback段全部寫在一個文件中,但是通過設(shè)置變量innodb_undo_tablespaces可以均勻分布多少個文件。這個變量的默認值是0,也就是說,所有的變量都被寫入一個表空間文件。此變量是靜態(tài)的,只能在數(shù)據(jù)庫示例停止時修改,例如寫入配置文件或在啟動時獲取相應的參數(shù)。
提交事務時,innodb不會立即刪除undolog,因為以后可能會用到它。例如,當隔離級別為repeatableread時,事務在啟動時讀取最新提交的行版本。只要交易沒有完成,就不能刪除行版本,也就是不能刪除undolog。
但是在提交事務時,該事務對應的undolog會被放入刪除列表,以后會通過purge刪除。并且在事務提交時,還會判斷undolog分配的頁面是否可以重用,如果可以重用,就分配給后續(xù)的事務,避免為每個獨立的事務分配獨立的undolog頁面而浪費存儲空間和性能。
刪除和更新操作的結(jié)果由undolog記錄,發(fā)現(xiàn)(插入操作不需要分析,只插入行)。
實際上刪除操作并不會直接刪除,只是刪除對象會被標記為delete,最后的刪除操作會由purge線程完成。更新分為兩種情況:更新的列是否是主鍵列。如果不是主鍵列,如何更新直接記錄在undolog中,即直接進行更新;如果是主鍵列,更新分兩部分執(zhí)行:首先刪除行,然后插入目標行。undolog包含舊版本數(shù)據(jù)行的快照信息,存儲在表空間中。
binlog和事務日志如下圖所示。提交事務時,寫入日志涉及三個步驟:
寫入重做日志,在準備狀態(tài)下寫入二進制日志,并將重做日志的狀態(tài)修改為提交。這里我們注意到重做日志的提交過程中引入了兩階段提交。為什么一定要有一個 兩階段提交和提交;?這是為了使兩個日志之間的邏輯一致。
因為redolog和binlog是兩個獨立的邏輯,如果你不 如果你不需要分兩個階段提交,你可以先完成重做日志然后再寫binlog,或者采用相反的順序。讓 讓我們看看這兩種方有什么問題,并用上面的更新示例進行假設(shè):
先寫redolog,再寫binlog。假設(shè)redolog完成,binlog未完成時,mysql進程異常重啟。因為已經(jīng)寫了redolog,系統(tǒng)還是可以崩潰的。把數(shù)據(jù)拿回來。但是binlog中沒有這個語句的記錄,所以備份日志時binlog中沒有這個語句;如果您需要使用此binlog來恢復臨時庫,則恢復的值與原始庫值不同,因為此語句的binlog已丟失。先寫binlog,再寫redolog。如果在binlog完成寫入后關(guān)閉,則該行的值不會更新,因為redolog尚未寫入,并且該事務在崩潰恢復后無效。但崩潰前的更新記錄已經(jīng)記錄在binlog中,當binlog來恢復時,又多出了一個事務,與原庫的值不同??梢钥闯?,兩階段提交是為了防止binlog和redolog不一致。同時我們也注意到,為了崩潰恢復的一致性,引入了很多新的東西,也讓系統(tǒng)復雜了很多,所以有得有失。在兩階段提交redolog和binlog的過程中,2pc事務的xid(事務落xid(redolog和binlog)的標識)將在兩者刷新后被記錄。如果數(shù)據(jù)庫崩潰正在進行中,提交和回滾將在通過xid進行恢復的過程中決定。詳細步驟見下一段恢復步驟 。
如果恢復步驟redolog中的事務經(jīng)過了兩階段提交中的準備階段,它將被標記為準備標志,如果它經(jīng)過了提交階段,它將被標記為提交標志(此時redolog和binlog都已關(guān)閉):
依次掃描redolog,如果redolog中的事務同時有準備和提交標記,則直接提交(將redolog磁盤中的數(shù)據(jù)頁復制到磁盤數(shù)據(jù)頁);如果重做日志事務只有準備標識符而沒有提交標識符,則意味著當前事務在提交階段已經(jīng)崩潰,重做日志中的當前事務是否完成是未知的。此時,取redolog中當前事務的xid(落在redolog和binlog中的事務的標識符)檢查binlog中是否存在此xid:如果binlog中存在當前事務的xid,則提交事務(將redolog磁盤中的數(shù)據(jù)頁復制到磁盤數(shù)據(jù)頁)。如果binlog中沒有當前事務的xid,則回滾事務(使用undolog刪除redolog中對應的事務);我們可以將mysql中redolog和binlog的兩階段提交與廣義上的兩階段提交進行比較。廣義來說,如果一個參與者在時限內(nèi)沒有收到協(xié)調(diào)器的ack通知,就會回滾,回滾邏輯要求開發(fā)者在每個參與者中記錄。mysql兩階段提交通過xid恢復。回復。
為了提高性能,組提交通常將多個相關(guān)的數(shù)據(jù)修改操作放在一個事務中,這樣可以避免為每個修改操作執(zhí)行一個完整的持久化操作。這種可以被認為是一種人為的群體行為。除了將多個操作合并在一個事務中,記錄binlog的操作也可以按照group的思想進行優(yōu)化:一次刷新多個事務涉及的binlog,而不是一次刷新一個binlog。
事務提交時,不僅會記錄事務日志,還會記錄二進制日志,但是誰先記錄它們呢?binlog是mysql的上層日志,寫在存儲引擎的事務日志之前。
在mysql5.6之前,事務提交時(即發(fā)出提交指令),mysql收到信號,進入提交準備階段;進入準備階段后,立即將binlog日志寫入內(nèi)存,將binlog日志寫入內(nèi)存后,相當于確定提交操作;然后開始在存儲器中寫入事務日志;最后擦洗binlog日志和事務日志,擦洗的分別由變量sync_binlog和innodb_flush_log_at_trx_commit控制。
但是為了保證binlog日志和事務日志的一致性,在提交后的準備階段會啟用一個prepare _ commit _ mutex鎖,以保證它們的順序和一致性。但是這樣會導致打開binlog日志后group commmit失效,尤其是在主從復制結(jié)構(gòu)中,binlog日志幾乎都是打開的。在mysql5.6中改進,提交事務時,事務會放入存儲引擎層上層結(jié)構(gòu)的隊列中。隊列中的第一個事務稱為領(lǐng)導者,其他事務稱為追隨者。領(lǐng)導者控制著追隨者的行為。雖然順序還是一樣,先刷binlog,再刷事務日志,但是機制完全變了:刪除了原來的prepare_commit_mutex行為,可以保證即使打開了binlog,組提交仍然有效。
mysql5.6中有三個步驟:刷新階段、同步階段和提交階段:
刷新階段:寫binlog將每筆交易存入內(nèi)存;同步階段:刷內(nèi)存中的binlog日志。如果隊列中有多個事務,那么只有一個fsync操作完成二進制日志的磁盤清理操作。這在mysql5.6中被稱為blgc(二進制日志組提交);提交階段:領(lǐng)導者按順序調(diào)用存儲引擎層事務。提交,因為innodb本來就支持組提交,解決了鎖定prepare_commit_mutex導致的組提交失效問題;binlog在flush階段寫入內(nèi)存,但寫入后并不進入sync階段,而是需要等待一定的時間,幾個事務的binlog會一起進入sync階段。等待時間由變量binlog_max_flush_queue_time決定,默認值為0,表示不等待就進入同步階段。將該變量設(shè)置為大于0的值的好處是組內(nèi)事務較多,性能會更好,但這樣會導致事務的響應時間較慢,所以建議不要修改該變量的值,除非有大量的事務并且不斷被寫入和更新。
進入同步階段,binlog會從內(nèi)存刷到磁盤,刷的多少由變量sync _ binlog控制,就像單個binlog刷一樣。
當一組事務處于提交階段時,其他新事務可以處于刷新階段,它們不會互相阻塞,因此組提交將繼續(xù)生效。當然,組提交的性能與隊列中的事務數(shù)量有關(guān)。如果隊列中一次只有一個事務,則組提交和單獨提交沒有區(qū)別。當隊列中的事務越來越多,即提交的事務越多,組提交的效果就越明顯。
我 m玉壺沈,歡迎關(guān)注我的官方賬號:wzm2zsd。
參考文檔mysql實戰(zhàn)45講br什么是walbr mysql事務日志(重做日志和撤銷日志)詳細分析br你說的——重做日志必須做的事情(一)br。
本文首發(fā)至官方賬號。保留所有權(quán)利。禁止轉(zhuǎn)載!
標簽:
日志交易
了解更多innodb重做日志(重做日志撤銷日志binlog)相關(guān)內(nèi)容請關(guān)注本站點。