InnoDB原子性和持久性
- 數(shù)據(jù)庫的原子性包括兩個內(nèi)容:災(zāi)難恢復(fù)和事務(wù)回滾。InnoDB通過redo日志來支持災(zāi)難恢復(fù)滑燃,通過undo日志來支持事務(wù)回滾示辈。
- 數(shù)據(jù)庫的持久性指事務(wù)一旦commit就會被持久化:通過在commit時同步寫入數(shù)據(jù)庫來支持。
redo日志:實(shí)現(xiàn)災(zāi)難恢復(fù)
- 為了更好的進(jìn)行持久化展哭,innodb使用WAL方式進(jìn)行持久化匪蟀,WAL通過將對數(shù)據(jù)的變更以追加的形式寫入日志椎麦,并且在之后將變更日志應(yīng)用到數(shù)據(jù)上,來將隨機(jī)IO盡可能地轉(zhuǎn)化為批量IO材彪,在innodb中观挎,這個叫做redo日志。
- 另外查刻,為了增加頻繁申請WALBuffer键兜,一般都會預(yù)設(shè)一個環(huán)形內(nèi)存Buffer區(qū)進(jìn)行重用凤类,在innodb中穗泵,這個叫做redo log buffer。
- innodb存在兩種類型的redo日志:物理日志直接記錄對頁的修改谜疤,而邏輯日志則記錄邏輯操作佃延,為了保證redo日志的冪等性,意味著夷磕,對于同樣狀態(tài)的物理頁履肃,應(yīng)用邏輯日志或者物理日志后生成的頁面數(shù)據(jù)應(yīng)該是一樣的。
- 在用戶線程中坐桩,一個事務(wù)包含多個語句尺棋,每個語句包含多個MTR,一個MTR是對底層頁面的一次完整訪問绵跷,由多個Redo日志組成膘螟;每次向redo log buffer寫入的基本粒度是一個MTR,這也是InnoDB引擎支持的最小并發(fā)粒度碾局;redo log被劃分為很多block荆残,每個block的大小為512字節(jié),等于一個扇區(qū)的大芯坏薄内斯;在commit或者其它時機(jī)蕴潦,redo log被刷入磁盤。
- lsn為內(nèi)存緩沖區(qū)已寫入的字節(jié)數(shù)俘闯,flushed_lsn為已刷新到磁盤的字節(jié)數(shù)潭苞,ckpt_lsn為已經(jīng)應(yīng)用到磁盤數(shù)據(jù)上的字節(jié)數(shù)。
- ckpt_lsn是通過FlushList進(jìn)行更新真朗,F(xiàn)lushList按page修改的最小的lsn進(jìn)行排序萄传,每當(dāng)隊尾page刷新到磁盤上時,ckpt_lsn都進(jìn)行更新蜜猾。
- 崩潰恢復(fù):通過ckpt_lsn秀菱,可以確定崩潰恢復(fù)的起點(diǎn),通過依次讀取redolog直到一個不足512字節(jié)的block蹭睡,則為崩潰恢復(fù)的終點(diǎn)衍菱,之后只要重新應(yīng)用redolog到磁盤數(shù)據(jù)即可。通過比較page的FIL_PAGE_LSN和將對同一個page的redo日志行為進(jìn)行劃分合并肩豁,可以減少恢復(fù)的時間脊串。
undo日志:回滾和MVCC
- B+樹索引數(shù)據(jù)中通過roll_pointer指向undo日志,uodate和delete類型的日志還有roll_pointer清钥,指向更早的undo日志琼锋,從而形成版本鏈,索引數(shù)據(jù)和undo日志中的trx_id用來實(shí)現(xiàn)不同的隔離級別祟昭,兩者結(jié)合缕坎,實(shí)現(xiàn)支持不同隔離級別的MVCC。
- 所有的undo日志都保存在undo日志段中篡悟,共有128個日志段谜叹,每個段中有1024個undo日志鏈,通過Page5中搬葬,可以找到128個undo日志段描述頁荷腊,通過undo日志段描述頁中的undoslots,可以找到1024個日志鏈急凰,每個日志鏈中包含多個undo日志頁女仰,以鏈表形式連接起來,第一個undo日志頁中不僅記錄undo日志抡锈,還記錄有undo日志鏈信息疾忍。
- 每個事務(wù)最多會使用4個日志鏈:普通表insert undo鏈;臨時表update undo鏈企孩;普通表insert undo鏈锭碳;臨時表update undo鏈。劃分四個不同類型的鏈的原因是:臨時表不需要寫redo日志勿璃,insert日志在事務(wù)提交后可直接釋放推汽,而update日志在事務(wù)提交后因需要支持MVCC不能直接釋放而需要等待purge線程清理后再釋放。
- 日志鏈滿足僅包含一個undo日志且使用量少于3/4時在事務(wù)提交后可以被重用歧沪,重用時歹撒,對于insert日志直接覆蓋寫,對于uodate日志诊胞,則通過使用UndoLogHeader中的nextLog和prevLog繼續(xù)增加新的Undo鏈信息追加寫暖夭。
- 為事務(wù)分配undo日志鏈的過程:
- 以輪轉(zhuǎn)方式從128個日志段中分配日志段
- 如果分配到的日志段中有可重用的日志鏈,則重用
- 若無撵孤,則以輪轉(zhuǎn)方式從1024個日志鏈中分配日志鏈