MySQL多版本並發控制分析,mysql版本並發

來源:互聯網
上載者:User

MySQL多版本並發控制分析,mysql版本並發

  • 讀未提交時,讀事務直接讀取主記錄,無論更新事務是否完成
  • READ_COMMITTED
    讀提交時,讀事務每次檢查主記錄上有沒有鎖,如果沒有鎖就讀取主記錄;如果有鎖,就讀取undo log中最近的版本。這樣每次讀到的都是最新COMMITTED的資料。因此兩次對同一欄位的讀可能讀到不同的資料(幻讀),但能保證每次都讀到最新的資料。
  • REPEATABLE_READ
    第一次讀的時候檢查主記錄上有沒有鎖,如果沒有鎖就讀取主記錄;如果有鎖,就讀取undo log中最近的版本。我猜測update的時候建立新的記錄,然後將原先主記錄內容拷貝到當前主記錄中,原先的主記錄就變為最新的undo log。以後每次都讀取第一次讀的版本,這樣保證不會產生幻讀,但可能讀不到最新的資料
  • SERIALIZABLE
    鎖表,讀寫相互阻塞,使用較少


Mysql到底是怎麼實現MVCC的?這個問題無數人都在問,但google中並無答案,本文嘗試從Mysql源碼中尋找答案。

  在Mysql中MVCC是在Innodb儲存引擎中得到支援的,Innodb為每行記錄都實現了三個隱藏欄位:

  • 6位元組的事務ID(DB_TRX_ID )
  • 7位元組的復原指標(DB_ROLL_PTR
  • 隱藏的ID
6位元組的事物ID用來標識該行所述的事務,7位元組的復原指標需要瞭解下Innodb的事務模型。
1. Innodb的事務相關概念為了支援事務,Innbodb引入了下面幾個概念:
  • redo log
    redo log就是儲存執行的SQL語句到一個指定的Log檔案,當Mysql執行recovery時重新執行redo log記錄的SQL操作即可。當用戶端執行每條SQL(更新語句)時,redo log會被首先寫入log buffer;當用戶端執行COMMIT命令時,log buffer中的內容會被視情況重新整理到磁碟。redo log在磁碟上作為一個獨立的檔案存在,即Innodb的log檔案。
  • undo log
    與redo log相反,undo log是為復原而用,具體內容就是copy事務前的資料庫內容(行)到undo buffer,在適合的時間把undo buffer中的內容重新整理到磁碟。undo buffer與redo buffer一樣,也是環形緩衝,但當緩衝滿的時候,undo buffer中的內容會也會被重新整理到磁碟;與redo log不同的是,磁碟上不存在單獨的undo log檔案,所有的undo log均存放在主ibd資料檔案中(資料表空間),即使用戶端設定了每表一個資料檔案也是如此。
  • rollback segment
    復原段這個概念來自Oracle的事物模型,在Innodb中,undo log被劃分為多個段,具體某行的undo log就儲存在某個段中,稱為復原段。可以認為undo log和復原段是同一意思。

  • Innodb提供了基於行的鎖,如果行的數量非常大,則在高並發下鎖的數量也可能會比較大,據Innodb文檔說,Innodb對鎖進行了空間有效最佳化,即使並發量高也不會導致記憶體耗盡。
    對行的鎖有分兩種:獨佔鎖定、共用鎖定。共用鎖定針對對,獨佔鎖定針對寫,完全等同讀寫鎖的概念。如果某個事務在更新某行(獨佔鎖定),則其他事物無論是讀還是寫本行都必須等待;如果某個事物讀某行(共用鎖定),則其他讀的事物無需等待,而寫事物則需等待。通過共用鎖定,保證了多讀之間的無等待性,但是鎖的應用又依賴Mysql的交易隔離等級。
  • 隔離等級
    隔離等級用來限制事務直接的互動程度,目前有幾個工業標準:
    - READ_UNCOMMITTED:髒讀
    - READ_COMMITTED:讀提交
    - REPEATABLE_READ:重複讀
    - SERIALIZABLE:序列化
    Innodb對四種類型都支援,髒讀和序列化應用情境不多,讀提交、重複讀用的比較廣泛,後面會介紹其實現方式。
2. 行的更新過程下面示範下事務對某行記錄的更新過程:1. 初始資料行
F1~F6是某行列的名字,1~6是其對應的資料。後面三個隱含欄位分別對應該行的事務號和復原指標,假如這條資料是剛INSERT的,可以認為ID為1,其他兩個欄位為空白。2.事務1更改該行的各欄位的值
當事務1更改該行的值時,會進行如下操作:
  • 用獨佔鎖定鎖定該行
  • 記錄redo log
  • 把該行修改前的值Copy到undo log,即中下面的行
  • 修改當前行的值,填寫事務編號,使復原指標指向undo log中的修改前的行
3.事務2修改該行的值
與事務1相同,此時undo log,中有有兩行記錄,並且通過復原指標連在一起。因此,如果undo log一直不刪除,則會通過目前記錄的復原指標回溯到該行建立時的初始內容,所幸的時在Innodb中存在purge線程,它會查詢那些比現在最老的活動事務還早的undo log,並刪除它們,從而保證undo log檔案不至於無限增長。4. 事務提交當事務正常提交時Innbod只需要更改事務狀態為COMMIT即可,不需做其他額外的工作,而Rollback則稍微複雜點,需要根據當前復原指標從undo log中找出事務修改前的版本,並恢複。如果事務影響的行非常多,復原則可能會變的效率不高,根據經驗值沒事務行數在1000~10000之間,Innodb效率還是非常高的。很顯然,Innodb是一個COMMIT效率比Rollback高的儲存引擎。據說,Postgress的實現恰好與此相反。5. Insert Undo log上述過程確切地說是描述了UPDATE的事務過程,其實undo log分insert和update undo log,因為insert時,原始的資料並不存在,所以復原時把insert undo log丟棄即可,而update undo log則必須遵守上述過程。3. 事務層級眾所周知地是更新(update、insert、delete)是一個事務過程,在Innodb中,查詢也是一個事務,唯讀事務。當讀寫事務並發訪問同一行資料時,能讀到什麼樣的內容則依賴事務層級:
  • READ_UNCOMMITTED
    讀未提交時,讀事務直接讀取主記錄,無論更新事務是否完成
  • READ_COMMITTED
    讀提交時,讀事務每次都讀取undo log中最近的版本,因此兩次對同一欄位的讀可能讀到不同的資料(幻讀),但能保證每次都讀到最新的資料。
  • REPEATABLE_READ
    每次都讀取指定的版本,這樣保證不會產生幻讀,但可能讀不到最新的資料
  • SERIALIZABLE
    鎖表,讀寫相互阻塞,使用較少
讀事務一般有SELECT語句觸發,在Innodb中保證其非阻塞,但帶FOR UPDATE的SELECT除外,帶FOR UPDATE的SELECT會對行加獨佔鎖定,等待更新事務完成後讀取其最新內容。就整個Innodb的設計目標來說,就是提供高效的、非阻塞的查詢操作。4. MVCC上述更新前建立undo log,根據各種策略讀取時非阻塞就是MVCC,undo log中的行就是MVCC中的多版本,這個可能與我們所理解的MVCC有較大的出入,一般我們認為MVCC有下面幾個特點:
  • 每行資料都存在一個版本,每次資料更新時都更新該版本
  • 修改時Copy出目前的版本隨意修改,個事務之間無幹擾
  • 儲存時比較版本號碼,如果成功(commit),則覆蓋原記錄;失敗則放棄copy(rollback)
就是每行都有版本號碼,儲存時根據版本號碼決定是否成功,聽起來含有樂觀鎖的味道。。。,而Innodb的實現方式是:
  • 事務以獨佔鎖定的形式修改未經處理資料
  • 把修改前的資料存放於undo log,通過復原指標與主要資料關聯
  • 修改成功(commit)啥都不做,失敗則恢複undo log中的資料(rollback)
二者最本質的區別是,當修改資料時是否要獨佔鎖定定,如果鎖定了還算不算是MVCC? 
Innodb的實現真算不上MVCC,因為並沒有實現核心的多版本共存,undo log中的內容只是序列化的結果,記錄了多個事務的過程,不屬於多版本共存。但理想的MVCC是難以實現的,當事務僅修改一行記錄使用理想的MVCC模式是沒有問題的,可以通過比較版本號碼進行復原;但當事務影響到多行資料時,理想的MVCC據無能為力了。
比如,如果Transaciton1執行理想的MVCC,修改Row1成功,而修改Row2失敗,此時需要復原Row1,但因為Row1沒有被鎖定,其資料可能又被Transaction2所修改,如果此時復原Row1的內容,則會破壞Transaction2的修改結果,導致Transaction2違反ACID。
理想MVCC難以實現的根本原因在於企圖通過樂觀鎖代替二段提交。修改兩行資料,但為了保證其一致性,與修改兩個分布式系統中的資料並無區別,而二提交是目前這種情境保證一致性的唯一手段。二段提交的本質是鎖定,樂觀鎖的本質是消除鎖定,二者矛盾,故理想的MVCC難以真正在實際中被應用,Innodb只是借了MVCC這個名字,提供了讀的非阻塞而已。5.總結也不是說MVCC就無處可用,對一些一致性要求不高的情境和對單一資料的操作的情境還是可以發揮作用的,比如多個事務同時更改使用者線上數,如果某個事務更新失敗則重新計算後重試,直至成功。這樣使用MVCC會極大地提高並發數,並消除線程鎖。6. 參考資料
  • Mysql官網
  • http://blog.chinaunix.net/link.php?url=http://forge.mysql.com%2Fwiki%2FMySQL_Internals
  • Understanding MySQL Internals

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.