0. MySql的3種日志
MySQL數據庫為什么可以實現主從復制,持久化,回滾的呢?
其實關鍵在於MySQL里的三種log,分別是:
- binlog - redo log - undo log
1. 什么是binlog
binlog是用於記錄數據庫表結構和表數據變更的二進制日志
eg:
insert、update、delete、create、truncate等等操作。
不會記錄select、show操作,因為沒有對數據本身發生變更。
-----------------------------------------------------------------------------------
binlog會記錄下每條變更的sql語句,還有執行開始時間,結束時間,事務id等等信息。
binlog是通過追加的方式進行寫入的,可以通過max_binlog_size參數設置每個binlog文件的大小,
當文件大小達到給定值之后,會生成新的文件來保存日志。
2. binlog詳細介紹
- 查看binlog是否打開
使用命令show variables like '%log_bin%'
- 開啟binlog
找到my.cnf配置文件,增加下面配置(mysql版本5.7.31):
# 打開binlog log-bin=mysql-bin # 選擇ROW(行)模式 binlog-format=ROW
修改后,重啟mysql,配置生效。
執行SHOW MASTER STATUS;可以查看當前寫入的binlog文件名。
- binlog使用場景
主從復制和數據恢復。
1. 主從復制: 在Master端開啟binlog, 從機訂閱binlog日志的信息。 然后將binlog發送到各個Slave端,Slave端重放binlog從而達到主從數據一致。 ----------------------------------------------------------------------------------- 2. 數據恢復: 通過使用mysqlbinlog工具來恢復數據。 指定--start-position和--stop-position,或者指定--start-datetime和--stop-datetime,那么就可以恢復指定區間的數據。
binlog主從復制(見下圖)
- binlog刷盤時機
對於InnoDB存儲引擎而言,只有在事務提交時才會記錄biglog,此時記錄還在內存中。 mysql通過sync_binlog參數控制biglog的刷盤時機, 取值范圍是0-N: 0:不去強制要求,由系統自行判斷何時寫入磁盤; 1:每次commit的時候都要將binlog寫入磁盤; N:每N個事務,才會將binlog寫入磁盤。 從上面可以看出,sync_binlog最安全的是設置是1,這也是MySQL 5.7.7之后版本的默認值。 但是設置一個大一些的值可以提升數據庫性能, 因此實際情況下也可以將值適當調大,犧牲一定的一致性來獲取更好的性能。
- binlog日志格式
binlog日志有三種格式,分別為STATMENT、ROW和MIXED。
在 MySQL 5.7.7之前,默認的格式是STATEMENT, MySQL 5.7.7之后,默認值是ROW。 ----------------------------------------------------------------------------------- 日志格式通過binlog-format指定。 STATMENT 基於SQL語句的復制(statement-based replication, SBR)。 每一條會修改數據的sql語句會記錄到binlog中。 優點:不需要記錄每一行的變化,減少了binlog日志量,節約了IO, 從而提高了性能; 缺點:在某些情況下會導致主從數據不一致,比如執行sysdate()、slepp()等。 ----------------------------------------------------------------------------------- ROW 基於行的復制(row-based replication, RBR)。 不記錄每條sql語句的上下文信息,僅需記錄哪條數據被修改了。 優點:不會出現某些特定情況下的存儲過程、或function、或trigger的調用和觸發無法被正確復制的問題; 缺點:會產生大量的日志,尤其是alter table的時候會讓日志暴漲 ----------------------------------------------------------------------------------- MIXED 基於STATMENT和ROW兩種模式的混合復制(mixed-based replication, MBR)。 一般的復制使用STATEMENT模式保存binlog,對於STATEMENT模式無法復制的操作使用ROW模式保存binlog。
3. redo log
為什么需要redo log?
事務的四大特性里面有一個是持久性,具體來說就是只要事務提交成功,那么對數據庫做的修改就被永久保存下來了, 不可能因為任何原因再回到原來的狀態。 那么mysql是如何保證一致性的呢?最簡單的做法是在每次事務提交的時候, 將該事務涉及修改的數據頁全部刷新到磁盤中。但是這么做會有嚴重的性能問題, 主要體現在兩個方面: 1. 因為Innodb是以頁為單位進行磁盤交互的,而一個事務很可能只修改一個數據頁里面的幾個字節, 這個時候將完整的數據頁刷到磁盤的話,太浪費資源了! 2. 一個事務可能涉及修改多個數據頁,並且這些數據頁在物理上並不連續,使用隨機IO寫入性能太差! 因此mysql設計了redo log, 具體來說就是只記錄事務對數據頁做了哪些修改, 這樣就能完美地解決性能問題了(相對而言文件更小並且是順序IO)。
redo log結構(見下圖)
redo log與binlog區別
4. undo log
undo log的作用主要用於回滾,mysql數據庫的事務的原子性就是通過undo log實現的。
我們都知道原子性是指對數據庫的一系列操作,要么全部成功,要么全部失敗。
undo log主要存儲的是數據的邏輯變化日志,比如說我們要insert一條數據,
那么undo log就會生成一條對應的delete日志。
簡單點說,undo log記錄的是數據修改之前的數據,因為需要支持回滾。
那么當需要回滾時,只需要利用undo log的日志就可以恢復到修改前的數據。
undo log另一個作用是實現多版本控制(MVCC),undo記錄中包含了記錄更改前的鏡像,
如果更改數據的事務未提交,對於隔離級別大於等於read commit的事務而言,
不應該返回更改后數據,而應該返回老版本的數據。