前面介紹了三種日誌:error log、slow log、binlog,這三種都是 Server 層的。今天的 redo log 是 InnoDB引擎專有的日誌文件。html
用個酒店掌櫃記帳的例子說明 redo log的做用。mysql
酒店掌櫃有一個粉板,專門用來記錄客人的賒帳記錄。若是賒帳的人很少,那麼他能夠把顧客名和帳目寫在板上。但若是賒帳的人多了,粉板總會有記不下的時候,這個時候掌櫃必定還有一個專門記錄賒帳的帳本sql
若是有人要賒帳或者還帳的話,掌櫃通常有兩種作法:數據庫
當生意火爆時,不停有人來要賒帳或者還帳(更新操做),若是掌櫃仍是用第一種作法,因爲記到帳本上須要查找記錄(隨機讀)那就會出現大量的人(更新操做)在等待,會影響工做(阻塞)。緩存
第二種作法,先記在粉板上,空閒時再寫回帳本。由於記粉板的速度是很快的,就能大量處理賒帳或者還帳,當掌櫃(MySQL)沒那麼忙的時候,就把粉板上的內容記到帳本上。但若是粉板(redo log)寫滿了,那這時候掌櫃(MySQL)就要停下工做,先去把粉板(redo log)的內容寫回帳本(磁盤)。性能
兩種作法的區別是:操作系統
所以MySQL採用第二種作法,當有一條記錄須要更新的時候,InnoDB引擎就會先把記錄寫到redo log(粉板)裏面,並更新內存,這個時候更新就算完成了。同時,InnoDB引擎會在適當的時候,將這個操做記錄更新到磁盤裏面,而這個更新每每是在系統比較空閒的時候作,這就像打烊之後掌櫃作的事。線程
這就是WAL(Write-Ahead Logging),先寫日誌,再寫磁盤。指針
與粉板相似,redo log 也是有固定大小的。好比能夠配置爲一組4個文件,每一個文件的大小是1GB,那麼這塊「粉板」總共就能夠記錄4GB的操做。從頭開始寫,寫到末尾就又回到開頭循環寫,以下面這個圖所示。日誌
兩個指針:
有了 redo log,InnoDB 能夠保證即便數據庫發生異常重啓,以前提交的記錄都不會丟失,這個能力稱爲 crash-safe。
下面以一條Update語句來介紹 binlog 是如何記錄的。這裏在 binlog 裏也有介紹過。
mysql> update T set c=c+1 where ID=2;
上面的流程採用了兩階段提交,那爲何要採用兩階段提交呢?是爲了讓 binlog 和 redo log 之間的邏輯一致。
咱們假設一下上面的 update 語句在執行的每一個時刻,MySQL 崩潰了,看一下兩個日誌間的邏輯是如何保持一致的。
這樣就能保證 redo log 和 binlog 的邏輯一致性。
兩階段提交是跨系統維持數據邏輯一致性時經常使用的一個方案。
這裏要介紹一下 redo log 裏很是重要的一個參數:innodb_flush_log_at_trx_commit
。
innodb_flush_log_at_trx_commit=0
表示提交事務的時候,不當即把 redo log buffer 裏的數據刷入磁盤文件的,而是依靠 InnoDB 的主線程每秒執行一次刷新到磁盤。此時可能你提交事務了,結果 mysql 宕機了,而後此時內存裏的數據所有丟失。
innodb_flush_log_at_trx_commit=1
表示提交事務的時候,就必須把 redo log 從內存刷入到磁盤文件裏去,只要事務提交成功,那麼 redo log 就必然在磁盤裏了。注意,由於操做系統的「延遲寫」特性,此時的刷入只是寫到了操做系統的緩衝區中,所以執行同步操做才能保證必定持久化到了硬盤中。
innodb_flush_log_at_trx_commit=2
表示提交事務的時候,把 redo 日誌寫入磁盤文件對應的 os cache 緩存裏去,而不是直接進入磁盤文件,可能 1 秒後纔會把 os cache 裏的數據寫入到磁盤文件裏去。
經過如下命令查看當前 innodb_flush_log_at_trx_commit
的值是多少:
mysql> select @@innodb_flush_log_at_trx_commit; +----------------------------------+ | @@innodb_flush_log_at_trx_commit | +----------------------------------+ | 1 | +----------------------------------+ 1 row in set (0.00 sec)
在 /etc/mysql/my.cnf
文件裏設置 innodb_flush_log_at_trx_commit
選項:
#/etc/mysql/my.cnf innodb_flush_log_at_trx_commit=1
修改後,重啓 MySQL 服務便可。