MySQL內核整理(一)

1、在共享表空間(系統表空間)中,innodb會維護一些系統信息:
一、Internal data dictionary
二、Rollback segments
三、undo space
四、insert buffer
五、Double write buffer
六、MySQL replication infomysql


2、Innodb索引結構:
一、全部的Innodb索引都是B+樹結構,索引記錄放在葉子節點.
二、data page頁默認16kb,當有新索引記錄寫入時,會預留1/16(1kb)空閒空間用於之後的索引記錄寫入
三、當索引記錄按照順序(正序、倒敘)寫入時,最理想的結果是索引頁能填充15/16;若是隨機無序寫入,則索引頁填充率可能會從1/2-15/16,當fill factor(填充因子)小於1/2時,會開始收縮數據頁,釋放空閒空間
四、5.6開始修改page size,支持4k、8k、16k、初始化時指定,後續沒法修改,不一樣page size的實例間也不能直接遷移使用.5.7開始擴展到32kb、64kb。
五、innodb表爲IOT,採用了B+樹類型,故每一個頁面至少存儲2行數據,若是行過大則會產生溢出;
六、理論上Innodb表中varchar(65535)的字節,但對於Innodb其實上限爲65532,且該值爲表全部varchar列長度總和;對於utf-8字符集,一個字符集佔3個字節,則其上限又縮小爲1/3;若是強制建立varchar(65535)的字段,在SQL_mode部位restricted的狀況下,其會被隱式轉換爲mediumtext;不管是varchar仍是blob/text,只要保證一個16k的頁面能容下2行數據,應該不會溢出;而一旦行溢出,字段前768字節(Antelope格式)依舊存放於當前頁面,數據通常使用B-tree Node頁,而溢出的行存放於Uncompress Blob頁;而barracuda採用了徹底行溢出,即只保留字段的前20字節.
七、當file format爲Antelope時,支持:REDUNDANT、COMPACT這兩種行格式.發生行溢出時,在當前page會存儲前768字節,多餘的放在off-page.
八、當file format爲Barracuda時,支持:compress,dynamic這兩種格式,併兼容前兩種,在當前page會存儲前20字節,多餘的放在off-page.
九、在多版本方式下,當你使用SQL語句刪除某一行的時候,該行並不會立刻從數據的物理文件上移除.只有當Innodb可以刪除掉更新日誌記錄的時候,那些行及其對應的索引記錄纔會真正從物理上刪除掉.這個移除操做稱爲purgeios

option:
innodb_file_format_max = barracuda
innodb_file_format = barracuda
要設置成同樣,而且同時最好把innodb_file_format_check設置爲1(默認值也是1),避免Innodb在啓動過程當中須要恢復數據,由於沒有檢查而寫入不支持格式的表中,致使數據丟失.
當file format 爲Antelope時,支持REDUNDANT、COMPACT這兩種行格式
當file format爲Barracuda時,支持:COMPRESS、DYNAMIC這兩種行格式,而且兼容前兩種sql

【重點】關於Innodb行格式的選擇
一、compact格式消耗磁盤空間和備份耗時最下,redundant相比之下略大一些.建議採用默認compact格式,適用於絕大數場景;
二、dynamic及compressed格式下.大字段數據存儲在off-page中,若是不須要讀取大字段效率較高,不然效率不好.所以count(*)之類的操做相對快,但進行備份須要全表掃描時,其代價反而更高;適用於不少大字段但無需常常被更新且備份的表.緩存

 

3、消除碎片
一、隨機方式插入新數據,可能致使輔助索引產生大量的碎片,意思是索引page和索引順序不接近,或者有大量的空洞. 執行alter table xxx engine = Innodb;能夠從新建立表空間,消除碎片、或者備份數據表,刪掉,從新導入服務器

4、回收表空間
一、共享表空間沒法在線回收,共享表空間想要回收的話,須要所有Innodb導出、刪除、導入,數據表空間用上面方法便可,或者直接清空不須要保存的歷史表,臨時表 truncate tableoop


5、Checkpoint
一、innodb會批量的把buffer pool中的髒頁以及redo log 刷新到磁盤,稱之爲檢查點.
二、並非在一次刷新中刷新全部的內容,由於這樣會下降mysql的性能,甚至沒法提供服務
三、在恢復的過程當中,innodb會向前掃描實務日誌,把這些髒數據刷新到磁盤中
四、innodb循環使用它的事務日誌,因此舊的日誌必然在將來某一時刻被覆蓋,innodb必須保證,在舊日誌被覆蓋以前,與這些舊日誌條目相關的髒數據都被刷新到了磁盤
五、若是這一點不能保證,萬一服務器crash,buffer pool中的髒頁就永遠也沒法恢復了.
六、因此在切換日誌的時候,innodb必然會作檢查點,把全部的髒頁都刷新到磁盤
七、從這個意義上,innodb的事物日誌越大,節省的磁盤IO越多,對系統性能越好.可是crash後恢復的時間確定會變長
八、innodb的檢查點每隔幾秒鐘就會作一次
九、只是通過日誌切換後,在日誌被衝用前,該日誌的內容必須被所有刷新到磁盤,不然系統就會hung住
十、嘗試用大一點的事務日誌,能夠減小檢查點過程當中寫磁盤的次數(之因此節省,是由於IO的合併)性能


Checkpoint觸發條件
一、每1秒,若buffer pool中的髒頁比率超過了srv_max_buf_pool_modified_pct = 75,則進行checkpoint,刷髒頁, flush PCT_IO(100)的dirty pages = 200(參數:innodb_io_capacity 可以對其定義);若採用adaptive flushing,則計算flush rate,進行必要的flush。
二、每10秒,若buffer pool中的髒頁比率超過了70%,flush PCT_IO(100)的dirty pages,若buffer pool中的髒頁比率未超過70%,flush PCT_IO(10%)的dirty pages = 20;每10s,一定調用一次log_checkpoint,作一次checkpointspa

髒頁比率 = 須要被flush的頁面數/(使用中的頁面數+空閒頁面數+1)
innodb_adaptive_flushing_lwm —設置redo log flush低水位線,當須要flush的redo log超過這個低水位時,當即強制啓用adaptive flushing,即使沒有設置使用adaptive flush 機制
innodb_io_capacity = N —-設置Innodb後臺進程最大的IO性能指標,列如:從buffer pool中刷新數據頁,從insert buffer中合併數據等.默認值200,在繁忙的OLTP模式下,須要適當提升.
innodb_io_capacity_max = N —設置Innodb_io_capacity_在緊急狀況下的上限值
innodb_flushing_avg_loops = N —-設置Innodb統計前N個page flush 速率,避免太快flush線程

 

【問題】Innodb都有哪些後臺進程?
後臺線程(15個)
一、master thread(1個)
二、lock monitor thread(1個)
三、error monitor thread(1個)
四、log thread(1個)
五、read/write thread(8個,默認各4個)
六、purge thread(1個)
七、page cleaner thread(1個)rest

 

以下source code:

master_thread_main_loop() loop: { //A、每秒須要執行的
    for(int i=0;i<10;i++) //sleep 1s //每秒都要刷新日誌緩存到磁盤
 { do log buffer flush to disk; } //若是緩存中的髒頁比例大於配置中的innodb_max_dirty_pages_pct就刷新innodb_io_capacity個髒頁到硬盤
    if(last_one_second_iosinnodb_max_dirty_pages_pct) { do buffer pool flush 100% innodb_io_capacity dirty page; } //若是沒有活躍用戶或者數據關閉時,就跳入background loop
if (no user activity){ goto background loop; } //有必要的話,就空閒1秒
sleep 1 second if necessary; } //B、每10秒須要執行的 //若是最後10s內IO小於innodb_io_capacity次,那麼就刷新innodb_io_capacity個髒頁到磁盤
if(last_ten_second_ios < innodb_io_capacity) { do buffer pool flush 100% * innodb_io_capacity dirty page; //老是合併最多5個插入
    do merge at most 5 insert buffer //老是將日誌緩存刷新到磁盤
    do log buffer flush to disk; //老是刪除buffer_pool中無用的undo頁,一次最多20個
    do full purge; } if (buf_get_modified_ratio_pct&get;70%) //若是緩存中髒頁比例大於70%,就刷新innodb_io_capacity個髒頁到磁盤,不然值只刷新10% * innodb_io_capacity個
{ do buffer pool flush 100% * innodb_io_capacity dirty page; } else { buffer pool flush 10% * innodb_io_capacity dirty page; //產生一個檢查點
    do checkpoint //返回主循環
    goto loop; } //backupgroud 循環
backupgroud loop; { //老是刪除buffer pool中無用的undo頁
    do full purge //老是合併innodb_io_capacity個插入緩存
    do merge 100% * innodb_io_capacity insert buffer //若是不空閒,就調回主循環,若是空閒就跳入flush loop
if not idle { goto loop: } else { goto flush loop; flush loop; //老是刷新innodb_io_capacity個髒頁到硬盤,知道緩存中的髒頁比例小於innodb_max_diry_pages_pct
    do buffer pool flush 100% * innodb_io_capacity dirty page if(buf_get_modified_ratio_pct&get;innodb_max_dirty_pages_pct) { goto flush loop; } //完成刷新髒頁的任務後,跳入suspend loop
    goto suspend loop; suspend loop: //將master線程掛起,等待事件激活
 { suspend_thread() waiting event } } }

master thread的線程優先級別最高.
其內部幾個循環(loop)組成:主循環(loop),後臺循環(background loop),刷新循環(flush loop),暫停循環(suspend loop)。
srv_master_thread loops: 8565077 srv_active, 0 srv_shutdown, 1939115 srv_idle
srv_master_thread log flush and writes: 10504192

master thread會根據數據運行的狀態在loop,background loop,flush loop和suspend loop中進行切換,loop稱爲主循環,由於大多數的操做都是在這個循環中,其中有兩個部分的操做:每秒的操做和每10秒的操做,loop循環經過thread sleep來實現,這意味着所謂的每一秒一次或者每10秒一次的操做是不精確的.固然,innodb源碼中還採用了其餘的方法來儘可能保證這個頻率.
@每秒一次操做包括:
一、日誌緩衝(log buffer)刷新到磁盤,即便這個事務尚未提交(老是)
二、合併插入緩衝(insert buffer)可能
三、之多刷新100個innodb的緩衝池(buffer pool)中的髒頁(dirty page)到磁盤(可能)
四、若是當前沒有用戶活動,切刀background loop(可能)

@每10秒操做包括:
一、刷新100個髒頁到磁盤(可能)
二、合併之多5個插入緩衝(老是)
三、將日誌緩衝刷新到磁盤(老是)
四、刪除無用undo頁(老是)
五、刷新100個或者10個髒頁到磁盤(老是)
六、產生一個檢查點(老是)

【重點】關鍵點:
一、dirty pages不要堆積太多,不然熱點數據不能被有效緩存,命中率低,而且瞬間大批量刷新dirty pages時也影響IOPS;
二、undo pages不要堆積太多,不然ibdata1可能暴漲,或者tsp受到影響;
三、checkpoint不要延遲太厲害,不然crash recovery進程很慢;
四、記住最重要的一點,這些後踢進程有條不紊按照固定頻率工做着,不要有停滯,也不要太頻繁.

相關文章
相關標籤/搜索