InnoDB體系架構(四)Master Thread工作方式
Master Thread工作方式
在前面的文章:InnoDB體系架構——後臺線程 說到:InnoDB存儲引擎的主要工作都是在一個單獨的後臺線程Master Thread中完成。這篇具體介紹該線程的具體實現及該線程可能存在的問題。
一、InnoDB1.0X版本之前的Master Thread
Master Thread具有最高的線程優先級別,內部由多個循環組成:主循環(loop)、後臺循環(background loop)、刷新循環(flush loop)、暫停循環(suspend loop),Master Thread會根據數據庫運行的狀態進行循環之間的切換。
Loop主循環(大多數操作都在這個循環下
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工作方式