
文章目錄
- redo log 和bin log有什麼差別?binlog做什麼用的
- 什麼是undolog,有什麼用?
- purge操作有什麼作用
- group commit有什麼好處,使用時需要注意什麼?
redo log 和bin log有什麼差別?binlog做什麼用的
在MySQL資料庫中還有一種二進制日志(binlog),其用來進行POINT-IN-TIME(PIT)的恢複及主從複制(Replication)環境的建立。從表面上看其和重做日志非常相似,都是記錄了對于資料庫操作的日志。然而,從本質上來看,兩者有着非常大的不同。首先,重做日志是在InnoDB存儲引擎層産生,而二進制日志是在MySQL資料庫的上層産生的,并且二進制日志不僅僅針對于InnoDB存儲引擎,MySQL資料庫中的任何存儲引擎對于資料庫的更改都會産生二進制日志。其次,兩種日志記錄的内容形式不同。MySQL資料庫上層的二進制日志bin log是一種邏輯日志,其記錄的是對應的SQL語句。而InnoDB存儲引擎層面的重做日志是實體格式日志,其記錄的是對于每個頁的修改。
什麼是undolog,有什麼用?
重做日志記錄了事務的行為,可以很好地通過其對頁進行“重做”操作。但是事務有時還需要進行復原操作,這時就需要undo。是以在對資料庫進行修改時,InnoDB存儲引擎不但會産生redo,還會産生一定量的undo。這樣如果使用者執行的事務或語句由于某種原因失敗了,又或者使用者用一條ROLLBACK語句請求復原,就可以利用這些undo資訊将資料復原到修改之前的樣子。redo存放在重做日志檔案中,與redo不同,undo存放在資料庫内部的一個特殊段(segment)中,這個段稱為undo段(undo segment)。undo段位于共享表空間内。可以通過py_innodb_page_info.py工具來檢視目前共享表空間中undo的數量除了復原操作,undo的另一個作用是MVCC,即在InnoDB存儲引擎中MVCC的實作是通過undo來完成。當使用者讀取一行記錄時,若該記錄已經被其他事務占用,目前事務可以通過undo讀取之前的行版本資訊,以此實作非鎖定讀取。最後也是最為重要的一點是,undo log會産生redo log,也就是undo log的産生會伴随着redolog的産生,這是因為undo log也需要持久性的保護。
purge操作有什麼作用
delete和update操作可能并不直接删除原有的資料。例如,DELETEFROMtWHEREa=1;表t上列a有聚集索引,列b上有輔助索引。對于上述的delete操作,僅是将主鍵列等于1的記錄deleteflag設定為1,記錄并沒有被删除,即記錄還是存在于B+樹中。其次,對輔助索引上a等于1,b等于1的記錄同沒有做任何處理。而真正删除這行記錄的操作其實被“延時”了,最終在purge操作中完成。purge用于最終完成delete和update操作。這樣設計是因為InnoDB存儲引擎支援MVCC,是以記錄不能在事務送出時立即進行處理。這時其他事物可能正在引用這行,故InnoDB存儲引擎需要儲存記錄之前的版本。而是否可以删除該條記錄通過purge來進行判斷。若該行記錄已不被任何其他事務引用,那麼就可以進行真正的delete操作。可見,purge操作是清理之前的delete和update操作,将上述操作“最終”完成。而實際執行的操作為delete操作,清理之前行記錄的版本。
group commit有什麼好處,使用時需要注意什麼?
若事務為非隻讀事務,則每次事務送出時需要進行一次fsync操作,以此保證重做日志都已經寫入磁盤。當資料庫發生當機時,可以通過重做日志進行恢複。雖然固态硬碟的出現提高了磁盤的性能,然而磁盤的fsync性能是有限的。
為了提高磁盤fsync的效率,目前資料庫都提供了group commit的功能,即一次fsync可以重新整理確定多個事務日志被寫入檔案。對于InnoDB存儲引擎來說,事務送出時會進行兩個階段的操作:1)修改記憶體中事務對應的資訊,并且将日志寫入重做日志緩沖。2)調用fsync将確定日志都從重做日志緩沖寫入磁盤。步驟2)相對步驟1)是一個較慢的過程,這是因為存儲引擎需要與磁盤打交道。但當有事務進行這個過程時,其他事務可以進行步驟1)的操作,正在送出的事物完成送出操作後,再次進行步驟2)時,可以将多個事務的重做日志通過一次fsync重新整理到磁盤,這樣就大大地減少了磁盤的壓力,進而提高了資料庫的整體性能。對于寫入或更新較為頻繁的操作,group commit的效果尤為明顯。然而在InnoDB1.2版本之前,在開啟二進制日志後,InnoDB存儲引擎的group commit功能會失效,進而導緻性能的下降。并且線上環境多使用replication環境,是以二進制日志的選項基本都為開啟狀态,是以這個問題尤為顯著導緻這個問題的原因是在開啟二進制日志後,為了保證存儲引擎層中的事務和二進制日志的一緻性,二者之間使用了兩階段事務。
1)當事務送出時InnoDB存儲引擎進行prepare操作。
2)MySQL資料庫上層寫入二進制日志。
3)InnoDB存儲引擎層将日志寫入重做日志檔案。
- a)修改記憶體中事務對應的資訊,并且将日志寫入重做日志緩沖。
- b)調用fsync将確定日志都從重做日志緩沖寫入磁盤。一旦步驟2)中的操作完成,就確定了事務的送出,即使在執行步驟3)時資料庫發生了當機。此外需要注意的是,每個步驟都需要進行一次fsync操作才能保證上下兩層資料的一緻性。步驟2)的fsync由參數sync_binlog控制,步驟3)的fsync由參數innodb_flush_log_at_trx_commit控制。
為了保證MySQL資料庫上層二進制日志的寫入順序和InnoDB層的事務送出順序一緻,MySQL資料庫内部使用了prepare_commit_mutex這個鎖。但是在啟用這個鎖之後,步驟3)中的步驟a)步不可以在其他事務執行步驟b)時進行,進而導緻了groupcommit失效。
這個問題最早在2010年的MySQL資料庫大會中提出,Facebook MySQL技術組,Percona公司都提出過解決方案。最後由MariaDB資料庫的開發人員Kristian Nielsen完成了最終的“完美”解決方案。在這種情況下,不但MySQL資料庫上層的二進制日志寫入是groupcommit的, InnoDB存儲引擎層也是group commit的。此外還移除了原先的鎖prepare_commit_mutex,進而大大提高了資料庫的整體性。MySQL5.6采用了類似的實作方式,并将其稱為Binary Log GroupCommit(BLGC)。MySQL 5.6 BLGC的實作方式是将事務送出的過程分為幾個步驟來完成。