undo日誌用來存放資料修改被修改前的值,假設修改tba 表中id=2的行數據,把Name='B' 修改為Name = 'B2' ,那麼undo日誌就會用來存放Name='B'的記錄,如果這個修改出現異常,可以使用undo日誌來實現回滾操作,並保證交易的一致性。
對資料的變更操作,主要來自INSERT UPDATE DELETE,而UNDO LOG分為兩種類型,一種是INSERT_UNDO(INSERT作業),記錄插入的唯一鍵值;一種是UPDATE_UNDO(包含UPDATE及DELETE操作),記錄修改的唯一鍵值以及old column記錄。
Id |
Name |
#1 |
A |
#2 |
B |
3 |
C |
##4 |
D
|
1.2 undo參數
MySQL跟undo有關的參數設定有這些:
mysql> show global variables like '%undo%';
+--------------------------+------------+
| Variable_name | Value |
+--------------------------+------------+
| innodb_max_undo_log_size | 1073741824 |
| innodb_undo_directory | ./ |
| innodb_undo_log_truncate | OFF |
| innodb_undo_logs | 128 |
| innodb_undo_tablespaces | 3 |
+--------------------------+------------+
mysql> show global variables like '%truncate%';
+--------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------+-------+
| innodb_purge_rseg_truncate_frequency | 128 |
| innodb_undo_log_truncate | OFF |
+--------------------------------------+-------+
#innodb_max_undo_log_size
innodb_undo_tablespaces
設定undo獨立表空間個數,範圍為0-128,預設為0,0表示表示不開啟獨立undo表空間且undo日誌儲存在ibdata檔案中。此參數只能在最開始初始化MySQL實例的時候指定,如果實例已創建,這個參數是不能變動的,如果在資料庫設定檔.cnf 中指定innodb_undo_tablespaces 的個數大於實例建立時的指定個數,則會啟動失敗,提示此參數設定有誤。
如果設定了該參數為n(n>0),那麼就會在undo目錄下建立n個undo檔案(undo001,undo002 ...... undo n),每個檔案預設大小為10M.
什麼時候需要來設定這個參數呢? innodb_undo_log_truncate
InnoDB的purge線程,根據innodb_undo_log_truncate設定開啟或關閉、innodb_max_undo_log_size的參數值,以及unc的頻率來進行空間回收和undo file 的重新初始化。
此參數生效的前提是,已設定獨立表空間且獨立表空間個數大於等於2個。 innodb_purge_rseg_truncate_frequency
用於控制purge回滾段的頻度,預設為128。假設設定為n,則說明,當Innodb Purge操作的協調執行緒 purge交易128次時,就會觸發一次History purge,檢查目前的undo log 表空間狀態是否會觸發truncate。
1.3 undo空間管理
如果需要設定獨立表空間,則需要在初始化資料庫實例的時候,指定獨立表空間的數量。
slot33-127,如果有獨立表空間,則預留給UNDO獨立表空間;如果沒有,則預留給系統表空間;
回滾段中除去32個提供給臨時表事務使用,剩下的128-32= 96個回滾段,可執行96*1024 個並發事務操作,每個事務佔用一個undo segment slot,注意,如果事務中有臨時表事務,還會在臨時表空間中的undo segment slot 再佔用一個undo segment slot,即佔用2個undo segment slot。若錯誤日誌中有:
Cannot find a free slot for an undo log。 ###則表示並發的事務太多了,需要考慮下是否要分流業務。 ######回滾段(rollback segment )採用輪詢調度的方式來分配使用,如果設定了獨立表空間,那麼就不會使用系統表空間回滾段中undo segment,而是使用獨立表空間的,同時,如果回顧段落正在Truncate操作,則不分配。 ###
2 redo
2.1 redo是什麼
當資料庫對資料做修改的時候,需要把資料頁從磁碟讀到buffer pool中,然後在buffer pool中進行修改,那麼這個時候buffer pool中的資料頁就與磁碟上的資料頁內容不一致,稱buffer pool的資料頁為dirty page 髒數據,如果這個時候發生非正常的DB服務重啟,那麼這些數據還沒在內存,並沒有同步到磁碟檔案中(注意,同步到磁碟檔案是個隨機IO),也就是會發生資料遺失,如果這個時候,能夠在有一個文件,當buffer pool 中的data page變更結束後,把相應修改記錄記錄到這個文件(注意,記錄日誌是順序IO),那麼當DB服務發生crash的情況,恢復DB的時候,也可以根據這個文件的記錄內容,重新套用到磁碟文件,資料保持一致。
這個檔案就是redo log ,用來記錄 資料修改後的記錄,順序記錄。它可以帶來這些好處:
假設修改tba 表中id=2的行數據,把Name='B' 修改為Name = 'B2' ,那麼redo日誌就會用來存放Name='B2'的記錄,如果這個修改在flush 到磁碟檔案時出現異常,可以使用redo log實作重做操作,確保交易的持久性。
Id |
Name |
#1 |
A |
#2 |
B |
3 |
C |
##4 |
D
|
這裡注意下redo log 跟binary log 的差別,redo log 是儲存引擎層產生的,而binary log是資料庫層產生的。假設一個大事務,對tba做10萬行的記錄插入,在這個過程中,一直不斷的往redo log順序記錄,而binary log不會記錄,知道這個事務提交,才會一次寫入到binary log文件中。有三種不同的記錄格式可供二進位日誌使用,分別是row、statement和mixed,它們之間的記錄形式各不相同。
2.2 redo 參數
#redo log 檔案的數量,命名方式如:ib_logfile0,iblogfile1... iblogfilen。預設2個,最大100個。
#檔案設定大小,預設值為48M,最大值為512G,注意最大值指的是整個redo log系列檔案之和,即(innodb_log_files_in_group * innodb_log_file_size )不能大於最大值512G。
檔案存放路徑
Redo Log 快取區,預設為8M,可設定1-8M。延遲交易日誌寫入磁碟,把redo log 放到該緩衝區,然後根據 innodb_flush_log_at_trx_commit參數的設置,再把日誌從buffer 中flush 到磁碟中。
##innodb_flush_log_at_trx_commit=1,每次commit都會把redo log從redo log buffer寫入到system,並fsync刷新到磁碟檔案中。 innodb_flush_log_at_trx_commit=2,每次交易提交時MySQL會把日誌從redo log buffer寫入到system,但只寫入到file system buffer,由系統內部來fsync到磁碟文件。如果資料庫實例crash,不會遺失redo log,但如果伺服器crash,由於file system buffer還來不及fsync到磁碟文件,所以會遺失這部分的資料。 innodb_flush_log_at_trx_commit=0,交易發生過程,日誌一直激勵在redo log buffer中,跟其他設定一樣,但是在交易提交時,不產生redo 寫入操作,而是MySQL內部每秒操作一次,從redo log buffer,把資料寫入到系統中去。如果發生crash,即丟失1s內的事務修改操作。
注意:由於進程調度策略問題,這個“每秒執行一次flush(刷到磁碟)操作”並不是保證100%的“每秒” 。
2.3 redo 空間管理##Redo log檔案以ib_logfile[number]
命名,Redo log 以順序的方式寫入檔案文件,寫滿時則回溯到第一個文件,進行覆蓋寫入。 (但在做redo checkpoint時,也會更新第一個日誌檔案的頭部checkpoint標記,所以嚴格來講也不算順序寫)。 事實上,redo日誌由兩個部分構成:redo日誌緩衝區和redo日誌檔案。 buffer pool中把資料修改狀況記錄到redo log buffer,出現以下情況,再把redo log刷下到redo log file:
##Redo log buffer空間不足
3.1 Undo Redo事務的簡化過程
假設有A、B兩個數據,值分別為1,2,開始一個事務,事務的操作內容為:把1修改為3,2修改為4,則實際的記錄如下(簡化): A.事務開始.
B.記錄A=1到undo log.
# C.修改A=3.
D.記錄A=3到redo log.
E.記錄B=2到undo log.
F.修改B= 4.
G.記錄B=4到redo log.
H.將redo log寫入磁碟。
I.事務提交
3.2 IO影響
設計Undo Redo的主要目的是提高輸入輸出效能,增加資料庫的處理能力。可以看出,B D E G H,都是新增操作,但是B D E G 是緩衝到buffer區,只有G是增加了IO操作,為了確保Redo Log能夠有比較好的IO性能,InnoDB 的Redo Log的設計有以下幾個特點:B. 盡量確保Redo Log儲存在連續的空間上。因此在系統第一次啟動時就會將日誌檔案的空間完全分配。為了提高效能,Redo Log會以順序IO的方式進行記錄,並且採用逐步添加的方式完成。
B. 批次寫入日誌。日誌並不是直接寫入文件,而是先寫入redo log buffer.當需要將日誌刷新到磁碟時 (如事務提交),將許多日誌一起寫入磁碟.
C. 並發的事務共享Redo Log的儲存空間,它們的Redo Log按語句的執行順序,依序交替的記錄在一起,以減少日誌所佔用的空間。例如,Redo Log中的記錄內容可能是這樣的:
記錄1:
記錄2:
記錄3:
記錄4:
記錄5:
D. 因為C的原因,當一個事務將Redo Log寫入磁碟時,也會將其他未提交的交易的日誌寫入磁碟。
E. Redo Log上只進行順序追加的操作,當一個交易需要回溯時,它的Redo Log記錄也不會從Redo Log中刪除掉。
3.3 恢復
前面說到未提交的事務和回滾了的事務也會記錄Redo Log,因此在進行恢復時,這些事務要進行特殊的的處理。有2種不同的恢復策略:
A. 進行恢復時,只重做已經提交了的交易。
在進行復原時,需要重新執行所有事務,包括未提交的和已回溯的事務。然後透過Undo Log回滾那些
未提交的事務。
MySQL資料庫InnoDB儲存引擎使用了B策略, InnoDB儲存引擎中的復原機制有幾個特點: A. 重做Redo Log時,並
不關心事務性。恢復時,沒有BEGIN,也沒有COMMIT,ROLLBACK的行為。也不關心每個日誌是哪個交易的。儘管事務ID等事務相關的內容會記入Redo Log,這些內容只是被當作要操作的資料的一部分。 B. 使用B策略就必須要將Undo Log持久化,而且必須在寫Redo Log之前將對應的Undo Log寫入磁碟。 Undo和Redo Log的這種關聯,使得持久化變得複雜。為了降低複雜度,InnoDB將Undo Log看作數據,因此記錄Undo Log的操作也會記錄到redo log中。透過將undo日誌快取在記憶體中,避免了在寫入redo日誌之前將其寫入磁碟的必要性。
包含Undo Log作業的Redo Log,看起來是這樣的: 記錄1: Undo log insert
; 記錄2: 記錄3: #Undo log insert
<undo_update …##Undo log insert <undo_update …##Undo log insert <undo_update …>#hellip;
記錄5: Undo log insert卷;trx3, delete …>
C. 到這裡,還有一個問題沒有弄清楚。既然Redo沒有事務性,那豈不是會重新執行被回滾了的事務?
確實是這樣。同時Innodb也會將交易回滾時的操作也會記錄到redo log中。在進行回滾操作時,資料的修改會被記錄到Redo Log中,因為回滾操作本質上也是對資料進行修改。
一個回滾了的事務的Redo Log,看起來是這樣的:
## 記錄1: >
記錄2: insert A…>
記錄3: ;trx1, update B…>
記錄5: >
C…> 記錄7: insert C
> 記錄8: update B
to old old #value> 記錄9: delete A>
一個被回滾了的事務在恢復時的操作就是先redo再undo,因此不會破壞數據的一致性。