# Mysql中的日志系統
Mysql中支持的日志有redo log、undo log、binlog(二進制日志文件)、error log、relay log;其日志系統相關的系統架構如下:
:-: 
說明:redo log和undo log是歸屬與innodb的,并不是所有存儲引擎都有。查詢緩存在mysql8之后就沒有了。innodb存儲引擎在5.5版本時候是`插件`的形式運行的,在5.5之后就成為了默認的存儲引擎。
## redo log
redo操作用于將數據重新恢復到新值,用于已經提交的事務當中。對于一個事務來說,執行commit語句之后并不能夠保證修改的數據真正的持久化到磁盤中,只能保證對應的redo log日志持久化到磁盤當中(因此redo log的落盤會在commit之前執行)。數據持久化真正持久化到磁盤是操作系統內核的行為。如果在數據還沒有真正的持久化到磁盤的時候系統掛了,內核中的臟頁數據將會丟失,這個時候就可以使用redo log來進行恢復了。
redo屬于存儲引擎(InnoDB)層管理的機制,在Buffer Pool中會維護一塊redo log pool的內存空間,當有DML語句執行的時候,會先將對應的日志內容寫入到redo log pool中,最后在執行commit時,會在redo log中做上commit標識,同時落盤。也就是說當事務被commit之后數據并不是真正的落盤了,有可能還在Buffer pool中,只能保證redo log的內容落盤了。這種方式就稱為WAL(write ahead log,預習日志)。而Buffer pool中的數據會在checkpoint中擇時落盤。
:-: 
**Redo log的落盤機制**
在配置文件中的Mycat中可以配置`innodb_flush_log_at_trx_commit`屬性來控制redo log的落盤機制,`innodb_flush_log_at_trx_commit`屬性的取值如下:
* 1,默認值,事務提交時執行一次fsync操作,將日志落盤。
* 0,事務提交時直將內容寫入redo log buffer中,由其他后臺線程選擇落盤的時機。
* 2,事務提交時將redo log的內容寫入pagecache中,之后每隔1秒由fsync命令刷新落盤。
可見設置為0的時候mysql的線程的性能最高,但是喪失了事務的一致性。為1的話就可以實現強一致性。
:-: 
> 問:redo log是不是都是已經提交的事務?
當事務提交的時候會將redo log的內容寫入redo log buffer中,這個時候并不是真正的寫入redo log的日志文件中的。redo log buffer落盤的時機受后臺線程的控制,由于redo log buffer是所有事務共享的且事務每次執行的命令的時候就會將命令寫入redo log中;當事務A執行到了一半,而事務B提交了事務或者是后臺線程刷新了redo log buffer中的臟頁,因此就有可能導致事務A的redo log的內容也被落盤了,但是此時事務A并沒有提交。
> 問:如何區分redo log中的事務是不是已經提交的事務?
對于一個修改x的命令,redo log的記錄內容大致可以如下:<事務ID,修改行,舊值,新值>。
對于一個完整的事務T1,redo log的內容可能如下:
```
<T1 start>
...
<T1 commit>
```
當事務執行commit命令之前會在redo log中打上commit標志,如果事務T1在redo log file中沒有最后的commit標志,是不用進行事務的恢復的。
> 問:checkpoint的作用是什么?
1. 在checkpoint之后開始或者提交的事務才需要進行恢復操作,可以縮短數據庫進行重做日志時的恢復時間。
2. 當緩沖池不夠用的時候,將臟頁刷新到磁盤中。
記錄的格式可能如下:
```
<checkpoint t1, t2,t3>
```
> 問:checkpoint什么時候起作用?
1. 數據庫關閉時將所有的臟頁落盤。
2. 主線程按照一定的時間刷新一定比例的臟頁。
3. LRU可用頁不多時。
4. 臟頁的數量超過一定的比例時。
> 問:doublewrite是什么?
由于InnoDB每頁的大小為16KB,而Linux文件系統支持的IO的最小單位是4K,磁盤IO的最小單位是512個字節,因此在臟頁落盤的時候如果發現了斷電而導致例如16KB只寫了2KB,這個時候就會出現數據丟失的問題,使用redo是不能夠恢復的。為了保證落盤這個過程的可靠性,InnoDB就引入了DoubleWrite機制,來解決部分寫入的問題。
DoubleWrite由兩部分組成,一個部分是內存中的DoubleWrite Buffer,大小為2MB;另外一部分是磁盤的共享表空間中連續的128個頁,大小也是2MB。double的過程如下:
1. 當發生臟頁落盤的時候,將臟頁copy到doublewrite中。
2. 接著從double write buffer中寫入順序寫入磁盤共享表空間中,每次1MB。
3. 做完之后將double write buffer中的數據寫入各個表空間中,離散寫入的。
在系統崩潰的時候在共享表空間中找到該頁的最近一個副本,直接替換。
> 問:為什么redo log不需要doublewrite的支持?
>
> redo log每次寫入的最小單位是512字節,也就是磁盤的最小單位。
## undo log
## binlog
binlog是Mysql server層維護的一種二進制文件,與redo log和undo log由存儲引擎層維護不同。其主要作用有:
* 主從復制:MySQL Replication在Master端開啟binlog,Master把它的二進制日志傳遞給slaves并回放來達到master-slave數據一致的目的。
* 數據恢復:通過mysqlbinlog工具恢復數據。
* 增量備份。
binlog文件的位置一般放在mysql安裝目錄下的data目錄,可以使用如下命令來具體查看binlog的狀態信息:
~~~
?show variables like '%log_bin%';
~~~
:-: 
在mysql5.7中binlog默認是關閉的,可以修改配置文件my.cnf啟動:
~~~
[mysqld]
log-bin=ON
~~~
查看binlog文件情況:
~~~
?show binary logs;
??
?show master status; # 查看當前寫入的binlog文件
??
?reset master; #清空binlog日志文件
~~~
:-: 
binlog文件是二進制文件,可以使用下面兩種方式查看binlog文件的內容:
1. mysqlbinlog
~~~
?mysqlbinlog binlog.000501
~~~
mysqlbinlog是官方提供的一個binlog的查看工具,windows系統在安裝目錄的bin目錄下有。
2. 直接命令行解析
~~~
?show binlog events [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count]
~~~
**binlog主從復制**
binlog主要用于主從復制中,在5.6版本之后有兩種主從復制方式:binlog和GTID(全局事務標識符)。binlog用于主從復制的流程如下:
1. Master將數據改變記錄到二進制日志(binary log)中。
2. Slave上的IO進程連接Master,并請求從指定日志文件的指定位置(或者從最開始的日志)之后的日志內容。
3. Master接收到來自Slave的IO進程的請求后,負責復制的IO進程會根據請求信息讀取日志指定位置之后的日志信息,返回給Slave的IO進程。返回信息中除了日志所包含的信息之外,還包括本次返回的信息已經到Master端的bin-log文件的名稱以及bin-log的位置。
4. Slave的IO進程接收到信息后,將接收到的日志內容依次添加到Slave端的relay-log文件的最末端,并將讀取到的Master端的 bin-log的件名和位置記錄到master-info文件中,以便在下一次讀取的時候能夠清楚的告訴Master從某個bin-log的哪個位置開始往后的日志內容。
5. Slave的Sql進程檢測到relay-log中新增加了內容后,會馬上解析relay-log的內容成為在Master端真實執行時候的那些可執行的內容,并在自身執行。
### 事務的兩階段提交
Mysql中有兩種日志是用于備份數據的,redo log和binlog;binlog是mysql的server層所有的,redo log是InnoDB引擎所有的,而只有redo log能用于故障恢復。因此為了保證redo log和binlog中的邏輯一致性,redo log會先寫入一個prepare標識,之后binlog寫入,之后再提交事務,寫入commit。
- 第一章 Java基礎
- ThreadLocal
- Java異常體系
- Java集合框架
- List接口及其實現類
- Queue接口及其實現類
- Set接口及其實現類
- Map接口及其實現類
- JDK1.8新特性
- Lambda表達式
- 常用函數式接口
- stream流
- 面試
- 第二章 Java虛擬機
- 第一節、運行時數據區
- 第二節、垃圾回收
- 第三節、類加載機制
- 第四節、類文件與字節碼指令
- 第五節、語法糖
- 第六節、運行期優化
- 面試常見問題
- 第三章 并發編程
- 第一節、Java中的線程
- 第二節、Java中的鎖
- 第三節、線程池
- 第四節、并發工具類
- AQS
- 第四章 網絡編程
- WebSocket協議
- Netty
- Netty入門
- Netty-自定義協議
- 面試題
- IO
- 網絡IO模型
- 第五章 操作系統
- IO
- 文件系統的相關概念
- Java幾種文件讀寫方式性能對比
- Socket
- 內存管理
- 進程、線程、協程
- IO模型的演化過程
- 第六章 計算機網絡
- 第七章 消息隊列
- RabbitMQ
- 第八章 開發框架
- Spring
- Spring事務
- Spring MVC
- Spring Boot
- Mybatis
- Mybatis-Plus
- Shiro
- 第九章 數據庫
- Mysql
- Mysql中的索引
- Mysql中的鎖
- 面試常見問題
- Mysql中的日志
- InnoDB存儲引擎
- 事務
- Redis
- redis的數據類型
- redis數據結構
- Redis主從復制
- 哨兵模式
- 面試題
- Spring Boot整合Lettuce+Redisson實現布隆過濾器
- 集群
- Redis網絡IO模型
- 第十章 設計模式
- 設計模式-七大原則
- 設計模式-單例模式
- 設計模式-備忘錄模式
- 設計模式-原型模式
- 設計模式-責任鏈模式
- 設計模式-過濾模式
- 設計模式-觀察者模式
- 設計模式-工廠方法模式
- 設計模式-抽象工廠模式
- 設計模式-代理模式
- 第十一章 后端開發常用工具、庫
- Docker
- Docker安裝Mysql
- 第十二章 中間件
- ZooKeeper