MySQL中的MVCC實現機制

 MySQL中的MVCC實現機制

   一、什麼是MVCC?

    MVCC,全稱Multi-Version Concurrency Control,即多版本併發控制。MVCC是一種無鎖的併發控制方法,一般在數據庫管理系統中,用於實現對數據庫的併發訪問。

    我們知道,在數據庫中,對數據的操作主要有2中,分別是讀和寫,而在併發場景下,就可能出現以下三種情況:

  •    讀-讀併發
  •    讀-寫併發
  •    寫-寫併發

    我們都知道,在沒有寫的情況下發讀-讀併發是不會出現問題的,而寫-寫併發這種情況比較常用的就是通過加鎖的方式實現。那麼,讀-寫併發則可以通過MVCC的機制解決。MVCC在MySQL InnoDB中的實現主要是爲了提高數據庫併發性能,用更好的方式去處理讀-寫衝突,做到即使有讀寫衝突時,也能做到不加鎖,非阻塞併發讀。本文就來介紹下一下MySQL中MVCC的實現機制。 

   二、快照讀和當前讀

   要想搞清楚MVCC的機制,最重要的一個概念那就是快照讀。

   1. 快照讀

   所謂快照讀,就是讀取的是快照數據,即快照生成的那一刻的數據,像我們常用的普通的SELECT語句在不加鎖情況下就是快照讀。如:

   SELECT * FROM xx_table WHERE ...

   2. 當前讀

   和快照讀相對應的另外一個概念叫做當前讀,當前讀就是讀取最新數據,所以,加鎖的 SELECT,或者對數據進行增刪改都會進行當前讀,比如:

   SELECT * FROM xx_table LOCK IN SHARE MODE;
   SELECT * FROM xx_table FOR UPDATE;
   INSERT INTO xx_table ...
   DELETE FROM xx_table ...
   UPDATE xx_table ...

   可以說快照讀是MVCC實現的基礎,而當前讀是悲觀鎖實現的基礎。

   那麼,快照讀讀到的快照是從哪裏讀到的的呢?換句話說,快照是存在哪裏的呢?

   三、undo log

   undo log是Mysql中比較重要的事務日誌之一,顧名思義,undo log是一種用於回退的日誌,在事務沒提交之前,MySQL會先記錄更新前的數據到 undo log日誌文件裏面,當事務回滾時或者數據庫崩潰時,可以利用 undo log來進行回退。

   這裏面提到的存在 undo log 中“更新前的數據”就是我們前面提到的快照。所以,這也是爲什麼說 undo log 是MVCC實現的重要手段的原因。

   那麼,一條記錄在同一時刻可能有多個事務在執行,那麼,undo log會有一條記錄的多個快照,那麼在這一時刻發生SELECT要進行快照讀的時候,要讀哪個快照呢?

   這就需要用到另外幾個信息了

   四、隱式字段

   其實,數據庫中的每行記錄中,除了保存了我們自己定義的一些字段以外,還有一些重要的隱式字段的:

   1. db_row_id

   隱藏主鍵,如果我們沒有給這個表創建主鍵,那麼會以這個字段來創建聚簇索引。
   2. db_trx_id

   對這條記錄做了最新一次修改的事務的ID(6字節)
   3. db_roll_ptr

   回滾指針(7字節),指向這條記錄的上一個版本,其實他指向的就是Undo Log中的上一個版本的快照的地址。
   因爲每一次記錄變更之前都會先存儲一份快照到undo log中,那麼這幾個隱式字段也會跟着記錄一起保存在undo log中,就這樣,每一個快照中都有有一個db_trx_id字段記錄了本次變更的事務ID,以及一個db_roll_ptr字段指向了上一個快照的地址。(db_trx_id和db_roll_ptr是重點,後面還會用到)。

   這樣,就形成了一個快照鏈表:   

   4. DELETED_BIT 

   刪除位(1字節), 記錄被更新或刪除並不代表真的刪除,而是刪除flag變了

   有了undo log,又有了幾個隱式字段,我們好像還是不知道具體應該讀取哪個快照,那怎麼辦呢?

   五、Read View

   這時候就需要Read View 登場了。Read View 主要來幫我們解決可見性的問題的, 即他會來告訴我們本次事務應該看到哪個快照,不應該看到哪個快照。

   1.  在 Read View 中有幾個重要的屬性

   1) trx_ids,系統當前未提交的事務 ID 的列表。

   2) low_limit_id,未提交的事務中最大的事務 ID。

   3) up_limit_id,未提交的事務中最小的事務 ID。

   4) creator_trx_id,創建這個 Read View 的事務 ID。

   每開啓一個事務,我們都會從數據庫中獲得一個事務 ID,這個事務 ID 是自增長的,通過 ID 大小,我們就可以判斷事務的時間順序。

   2.  那麼,一個事務應該看到哪些快照,不應該看到哪些快照該如何判斷呢?

   其實原則比較簡單,那就是事務ID大的事務應該能看到事務ID小的事務的變更結果,反之則不能。

   我們前面說過,每一條記錄上都有一個隱式字段db_trx_id記錄對這條記錄做了最新一次修改的事務的ID。那麼接下來,數據庫會拿這條記錄db_trx_id和Read View進行可見性比較。

   在創建 Read View 後,我們可以將記錄中的 db_trx_id 劃分這三種情況:

      

   1) db_trx_id < up_limit_id

   這種情況說明,表示這個版本的記錄是在創建 Read View 前已經提交的事務生成的,所以該版本的記錄對當前事務可見.

   2) db_trx_id>=low_limit_id
   這種情況說明,表示這個版本的記錄是在創建 Read View 後才啓動的事務生成的,所以該版本的記錄對當前事務不可見(不可見怎麼辦呢?後面講)

   3) up_limit_id < = db_trx_id < low_limit_id

   這種情況下,會再拿db_trx_id和Read View中的trx_ids進行逐一比較。

   如果db_trx_id 在trx_ids列表中,表示生成該版本記錄的活躍事務依然活躍着(還沒提交事務),所以該版本的記錄對當前事務不可見。

   如果db_trx_id不在trx_ids列表中,表示生成該版本記錄的活躍事務已經被提交,所以該版本的記錄對當前事務可見。

   所以,當讀取一條記錄的時候,經過以上判斷,發現記錄對當前事務可見,那麼就直接返回就行了。那麼如果不可見怎麼辦?沒錯,那就需要用到undo log了。

   當數據的事務ID不符合Read View規則時候,那就需要從undo log裏面獲取數據的歷史快照,然後數據快照的事務ID再來和Read View進行可見性比較,如果找到一條快照,則返回,找不到則返回空。

    六、MVCC和隔離級別

    其實,根據不同的事務隔離級別,Read View的創建和獲取時機是不同的

    1. 讀未提交

    數據庫不會創建 read view

    2. 讀提交

   在每個事務開始時,數據庫會創建一個 read view,用於記錄事務開始時數據庫中已提交事務的快照。這個 read view 會隨着事務的執行而逐漸變化,跟蹤新提交的事務以及舊事務的回滾。因此,每個事務都有自己獨立的 read view。

   一個事務中的每一次SELECT都會重新獲取一次Read View,

   3. 可重複讀

   在第一個查詢開始執行時,MySQL 會爲當前事務創建一個 read view,並在整個事務期間保持不變。這個 read view 記錄了事務開始時數據庫中已提交事務的快照。這意味着在同一個事務內的所有查詢都會看到相同的數據快照,即使其他事務提交了新的數據也不會影響。因此就不存在重複讀的問題了。

   一個事務中只在第一次SELECT的時候會獲取一次Read View。

   4. 串行化

   數據庫會在事務開始時創建一個 read view,並且在事務期間始終保持不變,類似於可重複讀隔離級別。

   七、總結 

   1.  MVCC的目的就是多版本併發控制,在數據庫中的實現,就是爲了解決讀寫衝突,它的實現原理主要是依賴記錄中的 4個隱式字段,undo日誌 ,Read View 來實現的。

   2. 在InnoDB中,MVCC就是通過Read View + Undo Log來實現的,undo log中保存了歷史快照,而Read View 用來判斷具體哪一個快照是可見的。

   總之,MVCC就是因爲設計者不滿意只讓數據庫採用悲觀鎖這樣性能不佳的形式去解決讀-寫衝突問題,而提出的解決方案,所以在數據庫中,因爲有了MVCC,所以我們可以形成兩個組合:

   1.  MVCC + 悲觀鎖 MVCC解決讀寫衝突,悲觀鎖解決寫寫衝突

   2. MVCC + 樂觀鎖 MVCC解決讀寫衝突,樂觀鎖解決寫寫衝突

   這種組合的方式就可以最大程度的提高數據庫併發性能,並解決讀寫衝突,和寫寫衝突導致的問題

 

   參考鏈接:

   https://www.51cto.com/article/719614.html
   https://xiaolincoding.com

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章