InnoDB存儲引擎之Master Thread

    InnoDB存儲引擎的主要工作都是在一個單獨的後臺線程Master Thread中完成的。
    1.InnoDB 1.0.x版本之前的Master Thread

        Master Thread具有最高的線程優先級別。其內部由多個循環組成:主循環(loop)、後臺循環(backgroup loop)、刷新循環(flush loop)、暫停循環(suspend loop)。Master Thread會根據數據庫運行的狀態在上述4狀態下進行切換。Loop被稱爲主循環,因爲大多數的操作是在這個循環中,其中有兩大部分的操作:每秒的操作和每10秒的操作。僞代碼如下:


        可以看到,loop循環通過thread sleep來實現,這意味着所謂的每秒一次或者每10秒一次的操作是不精確的。在負載很高的情況可能會有延遲,只能說大概在這個頻率下。當然InnoDB源代碼中還通過其他的方法來儘量保證這個頻率。
        每秒一次的操作:
            a.日誌緩衝刷新到磁盤,即使這個事務還沒有提交(總是);
                即使某個是我還沒有提交,InnoDB存儲引擎仍然每秒會將重做日誌緩衝中的內容刷新到重做日誌文件。這就可以解釋爲什麼再大的事務提交的時間也很短。
            b.合併插入緩衝(可能);
                合併插入緩衝(Insert Buffer)並不是每秒都會發生。InnoDB存儲引擎會判斷當前一秒內發生的IO次數是否小於5次,如果小於5次,InnoDB認爲當前的IO壓力很小,可以執行合併插入緩衝的操作。
            c.至多刷新100個InnoDB的緩衝池中的髒頁到磁盤(可能);
                InnoDB存儲引擎通過判斷當前緩衝池中髒頁的比例(buf_get_modified_ratio_pct)是否超過了配置文件中innodb_max_dirty_pages_pct這個參數的值,如果超過了這個閥值,InnoDB存儲引擎認爲需要做磁盤同步操作,將100個髒頁寫入磁盤。
            d.如果當前沒有用戶活動,則切換到background loop(可能);
        每10秒的操作:
            a.刷新100個髒頁到磁盤(可能);
            b.合併至多5個插入緩衝(總是);
            c.將日誌緩衝刷新到磁盤(總是);
            d.刪除無用的Undo頁(總是);
            e.刷新100個或者10個髒頁到磁盤(總是);
        在以上的過程中,InnoDB存儲引擎會先判斷過去10秒內磁盤的IO操作是否小於200次,如果是,InnoDB存儲引擎認爲當前有足夠的磁盤IO操作能力,因此將100個髒頁刷新到磁盤。接着,InnoDB存儲引擎會合並插入緩衝,不同於每秒一次操作時可能發生的合併插入緩衝操作,這次的合併插入緩衝總是會進行。之後InnoDB存儲引擎會在進行一次將日誌刷新到磁盤。這和每秒一次時發生的操作是一樣的。在接下來InnoDB存儲引擎會執行full purge操作,即刪除無用的Undo頁。在full purge過程中,InnoDB存儲引擎會判斷當前事務系統中已被刪除的行是否可以刪除,如果可以,則InnoDB會立即將其刪除。每次最多嘗試回收20個undo頁。然後,InnoDB存儲引擎會判定緩衝池中髒頁的比列如果有超過70%的髒頁,則刷新100個髒頁到磁盤。如果比例小於70%則只需要刷新10%的髒頁到磁盤。
        若當前沒有用戶活動(上鉅款空閒時)或者數據庫關閉(shutdown),就會切換到這個循環。background loop會會執行以下操作:
            a.刪除無用的Undo頁(總是);
            b.合併20個插入緩衝(總是);
            c.跳回到主循環(總是);
            d.不斷刷新100個頁直到符合條件(可能,跳轉到flush loop中完成);
        若flush loop中沒什麼事情可以做,InnoDB存儲引擎會切換到suspend loop,將Master Thread掛起,等待時間的發生。若用戶啓用(enable)了InnoDB存儲引擎,卻沒有使用任何InnoDB存儲引擎的表,那麼Master Thread總是處於掛起的狀態。
    2.InnoDB 1.2.x版本之前的Master Thread
        在InnoDB1.0.x版本之前,InnoDB存儲引擎對於IO其實是有限的,在緩衝池想磁盤刷新時其實都做了一定的硬編碼(hard coding)。在SSD出現之後,這種規定在很大程度上限制了InnoDB存儲引擎對磁盤IO的性能,尤其是寫入性能。從前面的介紹來看,無論何時,InnoDB存儲引擎最大隻會刷新100個頁到磁盤,合併20個插入緩衝。如果是在寫入密集的引用程序中,每秒可能會產生大於100個的髒頁,如果是產生大於20個插入緩衝的情況,Master Thread似乎總是會"忙不過來"。即使磁盤能在1秒內處理多餘100個頁的寫入和20個插入緩衝的合併,但是由於hard coding,Master Thread也只會選擇刷新100個髒頁和合並20個插入緩衝。同時,當發生宕機需要恢復是,由於很多數據還沒有刷新回磁盤,回到人恢復的時間肯能需要很久。針對這個問題InnoDB Plugin(從InnoDB1.0.x版本開始)提供了參數innodb_io_catacity,用來表示磁盤IO的吞吐量,默認200。對於刷新到磁盤頁的數量,會按照innodb_io_capacity的百分比來進行控制。規則如下:
            a.在合併插入緩衝時,合併插入緩衝的數量爲innodb_io_capacity值的50%;
            b.在從緩衝區刷新髒頁時,刷新的髒頁的數量爲innodb_io_capacity;
        若用戶使用了SSD類的磁盤,或者將幾塊磁盤做了RAID。當存儲設備擁有更高的IO速度是,可以將innodb_io_capacity的值調大寫,知道符合磁盤IO的吞吐量。InnoDB1.0.x版本的另一個參數innodb_adaptive_flushing(自適應地刷新),該值影響每秒刷新髒頁的數量。原來的刷新規則是:髒頁在緩存所佔比例小於innodb_max_dirty_pages_pct時,不刷新髒頁,大於innodb_max_dirty_pages_pct時,刷新100個髒頁。隨着innodb_adaptive_flushing參數的引入,InnoDB存儲引擎會通過一個buf_flush_get_desired_flush_rate的函數來判斷需要刷新髒頁最合適的數量。大致的做法是通過判斷產生重做日誌的速度來決定最合適的刷新髒頁數量。因此,當髒頁的比列小於innodb_max_dirty_pages_pct時,也會刷新一定量的髒頁。

        還有一個改變是:之前每次進行full purge操作時,最多回收20個Undo頁。從InnoDB1.0.x版本開始引入參數innodb_purge_batch_size,該參數可以控制每次full purge回收的Undo頁的數量,默認20。可以動態的對其進行修改。通過命令show engine innodb status可以查看檔期Master Thread的狀態信息。如下圖:


        有圖可知,主循環進行了1154432次,每秒掛起(sleep)的操作進行了1154432次,10秒一次的活動進行了106465次,background loop進行了90829次,flush loop進行了90829次。
    3.InnoDB 1.2.x版本的Master Thread
        InnoDB 1.2.x版本中,Master Thread的僞代碼如下:
           
        其中srv_master_do_idle_tasks()就是之前版本中每10秒的操作,srv_master_do_active_tasks()處理的是之前每秒中的操作。對於刷新髒頁的操作,從Master Thread線程分離到一個單獨的Page Cleaner Thread,從而減輕了Master Thread的工作,同時進一步提高了系統的併發性。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章