資料庫原理 - 序列5 - 事務是如何實現的? - Undo Log解析

来源:https://www.cnblogs.com/travis2046/archive/2019/04/15/10709347.html
-Advertisement-
Play Games

本文節選自作者書籍《軟體架構設計:大型網站技術架構與業務架構融合之道》。作者微信公眾號:架構之道與術。公眾號底部菜單有書友群可以加入,與作者和其他讀者進行深入討論。也可以在京東、天貓上購買紙質書籍。 6.6 事務實現原理之2:Undo Log 6.6.1 Undo Log是否一定需要 說到Undo ...


本文節選自作者書籍《軟體架構設計:大型網站技術架構與業務架構融合之道》。
作者微信公眾號:架構之道與術。公眾號底部菜單有書友群可以加入,與作者和其他讀者進行深入討論。也可以在京東、天貓上購買紙質書籍。

6.6 事務實現原理之2:Undo Log

6.6.1 Undo Log是否一定需要

說到Undo Log,很多人想到的只是“事務回滾”。“事務回滾”有四種場景:
場景1:人為回滾。事務執行到一半時發生異常,客戶端調用回滾,通知資料庫回滾,資料庫回滾成功。
場景 2:宕機回滾。事務執行到一半時資料庫宕機,重啟,需要回滾。
場景 3:人為回滾 + 宕機回滾。客戶端調用回滾,資料庫開始回滾數據,回滾到一半時資料庫宕機,重啟,繼續回滾。
場景 4:宕機回滾 + 宕機回滾。宕機重啟,在回滾的過程中再次宕機。

對於這四種場景的解決方法,在上文的ARIES演算法已經給出了答案,其中要用到Redo和Undo Log。這裡擴展一下,除了ARIES演算法,是否還有其他的方法可以做事務回滾?或者說,Undo Log是否一定需要?
回滾,就是取消已經執行的操作。無論從物理上取消,還是從邏輯上取消,只要能達到目的即可。假設Page數據都在記憶體裡面,每個事務執行,都只在記憶體中修改數據,必須等到事務Commit之後寫完Redo Log,再把Page數據刷盤。在這種策略下,不需要Undo Log也能實現數據回滾!因為在這種數據刷盤策略下,正好利用了“記憶體斷電消失”的特性,磁碟上存儲的全部是已經提交的數據,宕機重啟,記憶體中還未完成的事務自然被一筆勾銷了!在這種策略之下,未提交的事務不會進入Redo Log;未提交的事務,也不會刷盤,全都在記憶體裡面。
把這個展開,就是Page數據刷盤的四種策略,如表6-10所示。下麵對這四種策略進行詳細分析:

表6-10 Page數據刷盤的四種策略
在這裡插入圖片描述

No Steal和Steal:指未提交的事務是否可以寫入磁碟中?No Steal是未提交的事務不能寫入磁碟,只能在記憶體中操作,等到事務提交完,再把數據一次性寫入;Steal是指未提交的事務也能寫入,如果事務需要回滾,再更改磁碟上的數據。
No Force和Force: 是指已經提交的事務是否必須寫入磁碟?No Force是指已經提交的事務可以保留在記憶體里,暫時不用寫入磁碟;Force是指已經提交的事務必須強制寫入磁碟。

策略1:Force和No Steal。已經提交的事務必須強制寫入磁碟,未提交的事務,只能保留在記憶體里,等事務提交後再寫入磁碟,這種策略不需要Redo Log和Undo Log,僅靠數據本身就能實現原子性和持久性。但很顯然不可行,未提交的事務不能寫入磁碟,這還可以接受;已提交的事務必須強制寫入磁碟,這需要多次I/O,性能會受影響,所以才有了RedoLog。

策略2:No Force和No Steal。已提交的事務可以不立即寫入磁碟,未提交的事務只能保留在記憶體里。在這個策略下,只需要Redo Log即可,因為有“記憶體斷電消失”這個天然特性。

策略3:Force/Steal。已提交的事務立即寫入磁碟,未提交的事務也立即寫入磁碟。這種只需要UndoLog回滾宕機時未提交的事務,不需要Redo Log。但和策略1一樣,顯然不可行,多次I/O的性能會受影響。

策略4:No Force/Steal。第4種策略是我們最想要的,也是InnoDB實現的策略。就是已經提交的事務可以不立即寫入磁碟;未提交的事務可以立即寫入磁碟,也可以延遲寫入磁碟!再通俗一點,無論事務是否提交,既可以立即寫入磁碟,也可以不寫,寫入磁碟時機任意,想什麼時候寫就什麼時候寫。

策略1和策略3因為性能問題不能接受,所以必須要有Redo Log。而策略4和策略2都可以接受,但策略4比策略2好的地方在於提高了I/O效率。因為事務沒有提交,就開始寫入磁碟,等到提交事務的時候,要寫入磁碟的數據量會小,不然要把所有數據都累積到事務提交時再一次性寫入磁碟。
也正是因為現代的資料庫用的都是第4種,是最靈活的一種數據刷盤策略。在這種策略下,為了實現事務的原子性和持久性,才有瞭如此複雜的Redo Log和Undo Log機制,才有了上面的ARIES演算法。
除了在宕機恢復時對未提交的事務進行回滾,Undo Log還有兩個核心作用:
(1)實現ACID中I(隔離性)。
(2)高併發。

6.6.2 Undo Log(MVCC)

在多線程編程中,讀寫的併發問題有三種策略,如表6-9所示。
表6-11 併發讀寫的三種策略
在這裡插入圖片描述
在JDK的JUC代碼中,有CopyOnWriteArrayList和CopyOnWriteArraySet 兩個類,有興趣的讀者可以閱讀源碼來理解CopyOnWrite的思想。
對比上面表格的三種併發策略可以知道,從上到下,併發度越來越高。而InnoDB用的就是CopyOnWrite思想,是在Undo Log裡面實現的。每個事務修改記錄之前,都會先把該記錄拷貝一份出來,拷貝出來的這個備份存在Undo Log里。因為事務有唯一的編號ID,ID從小到大遞增,每一次修改,就是一個版本,因此Undo Log維護了數據的從舊到新的每個版本,各個版本之間的記錄通過鏈表串聯。

也正因為每條記錄都有多版本,才很容易實現事務ACID屬性中的I(隔離性)。事務要併發,多個事務要讀寫同一條記錄,為了實現第二個、第三個隔離級別,就不能讓事務讀取到正在修改的數據,而只能讀取歷史版本。
也正因為有了MVCC這種特性,通常的select語句都是不加鎖的,讀取的全部是數據的歷史版本,從而支撐高併發的查詢。這種讀,專業術語叫作“快照讀”,與之相對應的是“當前讀”。表6-10列舉了快照讀和當前讀對應的SQL語句,快照讀就是最常用的select語句,當前讀包括了加鎖的select語句和insert/update/delete語句。
表6-12 快照讀與當前讀對應的SQL語句
在這裡插入圖片描述

6.6.3 Undo Log不是Log

瞭解Undo Log的功能後,進一步來看Undo Log的結構。其實Undo Log這個詞有很大的迷惑性,它其實不是Log,而是數據。為什麼這麼說?
(1)Undo Log並不像Redo Log一樣按照LSN的編號,從小到大依次執行append操作。Undo Log其實沒有順序,多個事務是並行地向Undo Log中隨機寫入的。
(2)一個事務一旦Commit之後,數據就“固化”了,固化之後不可能再回滾。這意味著Undo Log只在事務Commit過程中有用,一旦事務Commit了,就可以刪掉UndoLog。具體來說:
對於insert記錄,沒有歷史版本數據,因此insert的Undo Log只記錄了該記錄的主鍵ID,當事務提交之後,該Undo Log就可以刪除了;
對於update/delete記錄,因為MVCC的存在,其歷史版本數據可能還被當前未提交的其他事務所引用,一旦未提交的事務提交了,其對應的Undo Log也就可以刪除了。
所以,更應該把UndoLog叫作記錄的“備份數據”,即在事務未提交之前的時間里的“備份數據”!提交事務後,沒有其他事務引用歷史版本了,就可以刪除了。

下麵來看這個“備份數據”是怎麼操作的。如圖6-18所示,Page中的每條記錄,除了自身的主鍵ID和數據外,還有兩個隱藏欄位:一個是修改該記錄的事務ID,一個是rollback_ptr,用來串聯所有的歷史版本。假設該記錄被tx_id為68、80、90、100的四個事務修改了四次,該數據就有四個版本,通過rollback_ptr從新到舊串聯起來。
然後,三個歷史版本分別被其他不同的事務讀取。為什麼會出現不同的事務讀取到不同的版本呢?因為T1、T2最先,此時歷史版本3是最新的,還沒有歷史版本1、2;之後該記錄被修改,產生了歷史版本2,然後出現了T3;之後該記錄又被修改,產生了歷史版本1,然後出現了T4。每個事務讀取的都是這個事務執行時最新的歷史版本。
這些歷史版本什麼時候可以刪除呢?在T1、T2提交之後,歷史版本3就可以刪除了;在T3提交之後,歷史版本2就可以刪除了,依此類推。
在這裡插入圖片描述
圖6-18 Undo Log邏輯結構
註意:在這裡有一個專業名詞,叫“回滾段”,很多描述Undo Log的文章花大篇幅描述它。但本書作者不想解釋這個名詞,因為它不僅不會幫助我們對原理的理解,還會把簡單問題複雜化。說得通俗一點,就是修改記錄之前先把記錄拷貝一份出來,然後拷貝出來的這些歷史版本形成一個鏈表,僅此而已。

6.6.4 Undo Log與Redo Log的關聯

Undo Log本身也要寫入磁碟,但一個事務修改多條記錄,產生多條Undo Log,不可能同步寫入磁碟,所以遇到了開篇講Write-Ahead時的問題。如何解決Undo Log需要多次寫入磁碟的效率問題呢?
Redo Log記錄的是對數據的修改,凡是對數據的修改,都必須記入Redo Log。可以把Undo Log也當作數據!在記憶體中記錄Undo Log,非同步地刷盤,宕機重啟,用Redo Log恢復Undo Log。
拿一個事務來舉例:

start transaction
  update表1某行記錄
  delete表1某行記錄
  insert表2某行記錄
commit

把Undo Log和Redo Log加進去,此事務類似下麵偽代碼所示:

start transaction
  寫Undo Log1: 備份該行數據(update)
  update表1某行記錄
  寫Redo Log1
  Undo Log2:備份該行數據(insert)
  delete 表1某行記錄
  寫Redo Log2
  Undo Log3:該行的主鍵ID(delete)
  insert表2某行記錄
寫Redo Log3
commit

在這裡,所有Undo Log和Redo Log的寫入都可以只在記憶體中進行,只要保證Commit之後Redo Log落盤即可,Undo Log可以一直保留在記憶體里,之後非同步刷盤。

文章太長,未完待續,接下來的1篇,會繼續分析Undo Log。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 資料庫操作-- 查看當前資料庫 SELECT DATABASE();-- 顯示當前時間、用戶名、資料庫版本 SELECT now(), user(), version();-- 創建庫 CREATE DATABASE[ IF NOT EXISTS] 資料庫名 資料庫選項 資料庫選項: CHARACT ...
  • MySQL資料庫引擎類別 能用的資料庫引擎取決於mysql在安裝的時候是如何被編譯的。要添加一個新的引擎,就必須重新編譯MYSQL。在預設情況下,MYSQL支持三個引擎:ISAM、MYISAM和HEAP。另外兩種類型INNODB和BERKLEY(BDB),也常常可以使用。 ISAM ISAM是一個定 ...
  • 前提已經安裝好hadoop的hdfs集群,可以查看 https://www.cnblogs.com/tree1123/p/10683570.html Mapreduce是hadoop的運算框架,可以對hdfs中的數據分開進行計算,先執行很多maptask,在執行reducetask,這個過程中任務的 ...
  • 快速查找所有存儲過程中是否包含某個字元串 ...
  • 一、通過SQL語句訪問遠程資料庫 --OPENROWSET函數 使用OPENROWSET()是個不錯的選擇,也可以用做跨庫查詢包括增、刪、改、查 下麵就來介紹一下OPENROWSET函數的運用 包含訪問 OLE DB 數據源中的遠程數據所需的全部連接信息。當訪問鏈接伺服器中的表時,這種方法是一種替代 ...
  • [20190415]11g下那些latch是共用的.txthttp://andreynikolaev.wordpress.com/2010/11/23/shared-latches-by-oracle-version/--//oracle並沒有文檔準確說明那些latch是支持共用,作者的鏈接通過使用 ...
  • 一臺老舊的資料庫伺服器(SQL Server 2005)突然報如下錯誤,而且資料庫處於RECOVERY PENDING ,檢查錯誤日誌,發現這個錯誤是突然出現的。沒有任何其它人為誤操作導致 Date 2019/4/15 10:57:47 Log SQL Server (Archive #1 - 20... ...
  • 《工業大數據白皮書(2019版)》基於工業大數據技術、產業發展現狀,重點圍繞“工業數據管理”這一熱點議題,提煉了當前工業領域數據管理的重要方法,完善了工業大數據標準體系,為推動工業大數據落地應用和戰略部署提供標準化支撐。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...