?在Innodb 事務詳解(1)當中我們介紹了什么是事務,以及事務需要滿住什么條件接下來我們來聊一聊inndb是如何實現(xiàn)事務的這些特性的文狱。
?在聊事務實現(xiàn)之前我們來先補充一些基礎知識。
1缘挽、WAL(預寫日志)
? 目前數據的持久化存儲都是依靠硬盤來實現(xiàn)的瞄崇,硬盤的內部結構是這個樣子的
?它有多個盤面,每個盤面上有一圈一圈的圓形的磁道壕曼,磁道被分為多個扇形的扇區(qū)苏研。扇區(qū)上存儲著我們的數據,從扇區(qū)讀寫數據是通過磁頭移到到指定的扇區(qū)上來操作的腮郊。讀寫數據時首先磁頭移動到指定的磁道上摹蘑,然后等待盤面旋轉使得磁頭正好位于我們想要操作的扇區(qū)上,這個步驟叫做尋址轧飞,然后磁頭開始對扇區(qū)進行讀寫操作衅鹿。
?磁盤的尋址需要盤面和磁頭的機械運動,這個過程相對于磁頭的讀寫數據來說是非常耗時的过咬。這種結構決定了磁盤在隨機讀寫的時候是相當慢的大渤,因為需要多次尋址,而在順序讀寫的時候是非常的快的掸绞,因為只需要一次尋址操作泵三。
?這里有個機械硬盤讀寫性能測試,順序讀寫比隨機讀寫快了90倍。
?可是在大多數使用場景下我們都需要對數據進行隨機讀寫的切黔,就拿數據庫來說吧砸脊,插入的時候為了讀得快肯定要進行排序具篇,排序就會發(fā)生后寫入得數據排在先寫入的數據前面的情況纬霞,這個時候肯定就有大量的隨機寫的操作。修改和讀取那就更不用說了驱显,肯定有大量的隨機操作诗芜。
?隨機操作硬盤太慢了那咋辦呢,那就把隨機操作轉換成連續(xù)操作埃疫,也就是現(xiàn)在大多數存儲系統(tǒng)使用的 WAL技術伏恐,原理很簡單,在內存當中保存數據的時候只在內存當中進行修改栓霜,硬盤上的數據先不動翠桦,為了防止內存當中的修改丟失,保存一條日志胳蛮,日志積累到了一定大小销凑,或者需要的時候順序寫入硬盤。內存當中的數據也不是一條一條存的而是分頁來存儲的仅炊,一頁當中有多條數據斗幼,寫入的時候就整頁寫,這樣就把隨機的硬盤操作變成了順序操作抚垄,大大提升了效率蜕窿。
整體思路有了還是有幾個細節(jié)上要處理 的問題
①?為了性能考慮 ,日志里面一般不會記錄真?zhèn)€內存頁的所有的數據呆馁,只會記錄增量的數據(哪些數據發(fā)生了變化)桐经。這樣問題就來了,當系統(tǒng)崩潰重啟的時候浙滤,我們從哪個日志開始來恢復硬盤中的數據次询,
?為了解決這個問題,一般采用的方式是每條日志都給上一個遞增的編號瓷叫,在實際數據頁當中也保存一個編號屯吊,這個編號和最后一次寫入這個數據頁的日志編號一樣,這樣恢復的時候用數據頁上的編號和日志上的編號進行對比摹菠,就能夠從正確的位置盒卸。
② 同樣也是為了性能考慮,一般內存中存儲的數據頁要比硬盤的最小寫入單元扇區(qū)大很多次氨,也就是寫入數據頁寫入硬盤的過程不是原子的蔽介。
為了解決這個問題,首先日志的大小需要設置成和扇區(qū)的大小一樣,保證每條日志的原子性(512字節(jié))虹蓄,一次的變更可以使用多條日志來表示犀呼。
在就是內存當中的數據頁刷入硬盤的時候 采用雙寫,每次刷多個數據頁的時候 先把這些數據頁進行順序寫入一個緩沖區(qū)薇组,這個過程是順序寫操作外臂,再把數據頁寫入實際存儲的位置后上去,當頁面刷入硬盤失敗的時候就可以直接從緩沖區(qū)恢復律胀。
原子性的實現(xiàn)
?那innodb原子性實現(xiàn)是不是只記錄一個日志就行了呢宋光,理論上貌似是可以是實現(xiàn)的,每次操作的時候記錄一條日志炭菌,需要回滾的時候讀取到相應的操作執(zhí)行相反的操作就行了罪佳,可是這樣做的性能不高,操作日志即數據庫中的redo log是整個庫通用的一個黑低,線上的數據庫通常一般操作會非常多赘艳,這就導致redo log數據量會非常的大,回滾操作的時候去讀取數據量這么大的redo log會非常的耗時克握,而且redo log 記錄的是物理日志蕾管,記錄的是某個內存頁發(fā)生了什么變化,而回滾是根據操作邏輯來的玛荞,是redolog 來記錄回滾信息顯然是不合適的娇掏。 于是在inndb當中專門為回滾設計了一個日志叫做 undo log,這個日志記錄的是邏輯日志,當操作修改和新增勋眯,刪除的時候相當于記錄了一個相反的操作婴梧,為了提升性能,undo log是按照事務id來存儲的客蹋,相同事務id的日志存儲在相同的槽當中塞蹭,這樣回滾的時候能夠快速找到日志,當事務提交的時候也能夠快速清理調日志內容讶坯。
?undo log的特性決定了它會涉及到大量的隨機讀寫操作番电,直接操作硬盤顯然不合適,那么如何保證undo log的持久性呢辆琅,不能說故障重啟之后undo log就丟了漱办,那沒提交的數據咋回滾。
?于是innodb給undo log 數據頁的操作也添加了redo log 寫undo log 之前先順序寫入redo log ,故障恢復時 先通過redo log 恢復undo log 在通過undo log來確定是否需要回滾婉烟。
&emps undo log redo log 的存在就確保了inndb的原子性娩井,在事務當中的存在執(zhí)行的時候 先寫undo log (先寫入 undo log 數據頁的redo log 再 修改undo log內存頁),在寫實際數據(先寫實際數據頁的redo log的似袁,在操作內存數據)當事務提交的時候洞辣,把redo log全部刷入硬盤就行了咐刨。需要回滾的時候根據事務id讀取到undo log 根據 undo log 來進行回滾操作 。
持久性的實現(xiàn)
?通過 WAL技術(redo log)即實現(xiàn)了持久性扬霜,每次操作之前寫記錄 redo log 事務提交的時候把日志刷入硬盤 實現(xiàn)了持久性定鸟。