1. 程式人生 > >InnoDB體系架構(四)Master Thread工作方式

InnoDB體系架構(四)Master Thread工作方式

延遲 理解 dir tex 任務 刪除 apc HA body

Master Thread工作方式

  在前面的文章:InnoDB體系架構——後臺線程 說到:InnoDB存儲引擎的主要工作都是在一個單獨的後臺線程Master Thread中完成。這篇具體介紹該線程的具體實現及該線程可能存在的問題。

一、InnoDB1.0X版本之前的Master Thread

  Master Thread具有最高的線程優先級別,內部由多個循環組成:主循環(loop)、後臺循環(background loop)、刷新循環(flush loop)、暫停循環(suspend loop),Master Thread會根據數據庫運行的狀態進行循環之間的切換。

  Loop主循環(大多數操作都在這個循環下

)這個由兩大部分操作,每秒每10秒操作:

void master_thread() {
    loop:
    for(int i=0; i<10; i++) {
        do thing once per second
        sleep 1 second if necessary
    }
    do things once per then seconds
    goto loop;
}

  可以發現,loop循環是通過thread sleep來實現的,意味著每秒或者每10每秒的操作並不是十分的精確的,在負載大的情況下,可能會有不同程度的延遲(delay)。

  每秒一次的操作包括:

1. 日誌緩沖刷新到磁盤(總是):即使事務沒有提交,InnoDB也會每秒將重做日誌緩沖刷新到重做日誌文件中,因此可以理解為什麽再大的事務提交,時間也是很短的。

2. 合並插入緩沖insert buffer(可能):並不是每秒刷新的,如果前一秒的IO次數小於5,則認為IO壓力小,可以執行合並插入緩沖的操作。

3. 最多刷新100個InnoDB的緩沖池臟頁到磁盤(可能):判斷當前緩沖池中臟頁的比例(buf_get_modifyed_ratio_pct)是否超過了配置文件中innodb_max_dirty_pages_pct這個參數(默認為90)如果超過了這個閾值,InnoDB存儲引擎認為需要做同步操作,將100個臟頁寫入磁盤中。

4. 如果當前沒有用戶活動,切換到background loop(可能)

  每10秒的操作:

1. 刷新100個臟頁到磁盤(可能)

2. 合並至多5個插入緩沖(總是)

3. 將日誌緩沖刷新到磁盤(總是)

4. 刪除無用的undo頁(總是):InnoDB存儲引擎會執行full purse操作,即刪除無用的Undo頁,對表進行update、delete這類操作,原先行被標記刪除,但是因為一致性讀讀關系,需要保留這些行的版本號,這時候會進行回收刪除。

5. 刷新100個或者10個臟頁到磁盤(總是)

  接著來看background loop 若當前沒有用戶活動(數據庫空閑時)或者數據庫關閉(shutdown),就會切換到這個循環執行以下操作:

1. 刪除無用的undo頁(總是)

2. 合並20個插入緩沖(總是)

3. 跳回到主循環(總是)

4. 不斷刷新100個頁,直到符合條件(可能,跳轉到flush loop中完成):如果fulsh loop 頁沒有什麽事情可以做了,InnoDB存儲引擎會切換到suspend loop,將Master Thread刮起。

二、InnoDB1.2.X之前的版本的Master Thread

  在如今磁盤技術的快速發展中,對於緩沖池向磁盤刷新時都做了一定的hard coding,這些限制很大程度上限制了InnoDB存儲引擎對磁盤IO的性能,尤其是寫入性能。

  因此提供參數innodb_io_capacity用來表示IO的吞吐量,默認200,對於刷新到磁盤頁的數量,會按照innodb_io_capacity的百分比來控制:

    在合並插入緩沖時,合並插入緩沖的數量為innodb_io_capacity值5%;

    在從緩沖池刷新臟頁時,刷行臟頁的數量為innodb_io_capcity;

  通過以下為代碼,我們可以得到InnoDB1.2X前Master Thread的工作方式:

void master_thread() {
    loop:
    for(int i=0; i<10; i++) {
        thread_sleep(1)    // sleep 1秒
        do log buffer flush to dish

        if (last_one_second_ios < 5% innodb_io_capacity) {
            do merget 5% innodb_io_capacity insert buffer
        }

        if (buf_get_modified_ratio_pct > innodb_max_dirty_pages_pct) {  // 如果緩沖池中的臟頁比例大於innodb_max_dirty_pages_pct(默認是75時)
            do buffer pool flush 100% innodb_io_capacity dirty page  // 刷新全部臟頁到磁盤
        } else if (enable adaptive flush) {    // 如果開戶了自適應刷新
            do buffer pool flush desired amount dirty page // 通過判斷產生redo log的速度決定最合適的刷新臟頁的數量
        }

        if (no user activetuy) {
            goto background loop
        }
    }

    if (last_ten_second_ios < innodb_io_capacity) {  // 如果過去10內磁盤IO次數小於設置的innodb_io_capacity的值(默認是200)
        do buffer pool flush 100%  innodb_io_capacity dirty page
    }

    do merge 5% innodb_io_capacity insert buffer  // 合並插入緩沖是innodb_io_capacity的5%(10)(總是)
    do log buffer flush to dish
    do flush purge

    if (buf_get_modified_ratio_pct > 70%) {
        do buffer pool flush 100% innodb_io_capacity dirty page
    } else {
        do buffer pool flush 10% innodb_io_capacity dirty page
    }
    goto loop

    backgroud loop:   // 後臺循環
    do full purge     // 刪除無用的undo頁 (總是)
    do merger 5% innodb_io_capacity insert buffer  // 合並插入緩沖是innodb_io_capacity的5%(10)(總是)
    if not idle:      // 如果不空閑,就跳回主循環,如果空閑就跳入flush loop
    goto loop:    // 跳到主循環
    else:
        goto flush loop
    flush loop:  // 刷新循環
    do buf_get_modified_ratio_pct pool flush 100% innodb_io_capacity dirty page // 刷新200個臟頁到磁盤
    if ( buf_get_modified_ratio_pct > innodb_max_dirty_pages_pct ) // 如果緩沖池中的臟頁比例大於innodb_max_dirty_pages_pct的值(默認75%)
        goto flush loop            // 跳到刷新循環,不斷刷新臟頁,直到符合條件
        goto suspend loop          // 完成刷新臟頁的任務後,跳入suspend loop
    suspend loop:
    suspend_thread()               //master線程掛起,等待事件發生
    waiting event
    goto loop;
}

三、InnoDB1.2.x版本的Master Thread

if (InnoDB is idle) {
    srv_master_do_idle_tasks();    // 每10秒操作
} else {
    srv_master_do_active_tasks();    // 每秒操作
}

InnoDB體系架構(四)Master Thread工作方式