首先innodb 線程分爲用戶態線程和後臺線程,用戶態線程主要是用戶操作的線程,可以通過show process list 查看,後臺線程不能夠查看。但是show innodb status可以查看到4個線程
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (write thread)
IO線程是可以通過innodb_file_io_threads 參數配置,默認是4;
其次innodb 刷數據也分兩種,同步IO及一步IO就是show innodb status 中出現的aio;
在innodb中後臺線程刷數據時異步IO,後臺線程受主線程master_thread調度;master_thread 優先級最高,其內部由幾個循環構成
主 loop ,background loop,flush loop;suspend loop;master thread 運行會在這幾個線程之間切換;
首先說 主loop,主loop 分爲兩類主要操作,每1s和每10s,但是innodb 並不是嚴格按照這個時段來執行的,因爲中間出了切換還有sleep等操作會消耗時間;
在innodb中維護了4個隊列,每個隊列長度256,其中存放的是slot,當隊列滿時,必然會喚醒相關的IO線程執行相應的iO操作,主線程也會週期性的喚醒IO線程;然後檢查自己的隊列,看是否需要做刷盤操作; 這4個線程是異步IO;
每1s喚醒IO線程執行操作
1、日誌緩衝刷新到磁盤,每1s 執行,同時日誌緩衝會受到innodb_flush_log_at_trx_commit 參數配置的影響,但是即使事務沒有提交,也會刷,在刷日誌時,innodb會對時間做一個判斷,首先先看有沒有在隊列裏超過2s的 如果有 就先刷他們,如果沒有超過2s的 也先刷低地址的,然後會遍歷隊列 把幾個在同一個extent的page一起刷下去;
2、合併插入緩衝(可能);innodb會判斷當前IO情況,如果當前1s內少於5次IO,它就認爲當前IO負載較小,執行合併插入;
3、刷新至多100個髒數據頁(可能);如果當前髒頁操過了90%,就是innodb_max_dirty_pages_pct 默認值,那麼它認爲需要刷新髒頁
4、切換到background loop;
每10s喚醒IO線程執行的操作
1、將日誌緩衝刷新到磁盤;
2、合併5個插入緩衝;不管當前IO操作能力如何,總是強制執行;
3、刷新100個髒頁;innodb會判斷過去10s內IO操作是否小於200,如果是,那麼它認爲當前IO比較輕,執行刷新100個髒頁;如果當前髒頁比例大於70%,那麼也會刷新100個髒頁,否則會刷新10個;
4、刪除無用的undo頁;因爲innodb採用了MVCC機制,有些爲了一致性讀而被標記爲刪除狀態數據頁需要被清理,比如有時一個查詢可能需要讀取前一個版本的數據信息,它被放在undo頁中;但是每次最多刪除20個undo頁;
5、產生一個檢查點;innodb 刷數據時會產生一個檢查點;但是沒10s也會強制產生一個檢查點;爲了保證性能,並不是完全刷完髒數據,而是志將最老日誌序列號的頁刷盤;
background loop ,當前沒有或用用戶或者數據庫關閉時就會切換到這個循環;
它會執行以下操作;
1、刪除無用的 undo頁;
2、合併20個插入緩衝;
3、不斷刷新100個數據頁,知道符合條件(可能跳到 flush loop 中完成);
suspend_loop
如果 flush loop中也沒有什麼事情可以做了,innodb 會切換到 suspeng_loop,將master thread掛起,等待事件的發生;如果啓用了innodb 存儲引擎卻沒有innodb表,通用也會將 master thread 掛起;
主線程如下
10 do buffer pool flush 100 dirty page
11 if ( no user activity )
12 goto backgroud loop
13 }
14 if ( last_ten_second_ios < 200 )
15 do buffer pool flush 100 dirty page
16 do merge at most 5 insert buffer
17 do log buffer flush to disk
18 do full purge
19 if ( buf_get_modified_ratio_pct > 70% )
20 do buffer pool flush 100 dirty page
21 else
22 buffer pool flush 10 dirty page
23 do fuzzy checkpoint
24 goto loop
25 background loop:
26 do full purge
27 do merge 20 insert buffer
28 if not idle:
29 goto loop:
30 else:
31 goto flush loop
32 flush loop:
33 do buffer pool flush 100 dirty page
34 if ( buf_get_modified_ratio_pct> innodb_max_dirty_pages_pct )
35 goto flush loop
36 goto suspend loop
37 suspend loop:
38 suspend_thread()
39 waiting event
40 goto loop;
後續會對innodb plugin 說明
上面說到 的主線程部分大多數是異步IO ,但是用戶態線程大多數是同步IO;
當你發起一個事務時,innodb會判斷log buffer 是否有足夠的空間;如果有那麼就啓動一個事務,如果沒有,那麼就會喚醒log thread 刷日誌,但是並不刷完;同時也會對髒頁做類似處理;
參考 innodb 存儲引擎內幕一書及自己一些學習;