MySQL內核整理(一)


一、在共享表空間(系統表空間)中,innodb會維護一些系統信息:
1、Internal data dictionary
2、Rollback segments
3、undo space
4、insert buffer
5、Double write buffer
6、MySQL replication info


二、Innodb索引結構:
1、所有的Innodb索引都是B+樹結構,索引記錄放在葉子節點.
2、data page頁默認16kb,當有新索引記錄寫入時,會預留1/16(1kb)空閑空間用於以后的索引記錄寫入
3、當索引記錄按照順序(正序、倒敘)寫入時,最理想的結果是索引頁能填充15/16;如果隨機無序寫入,則索引頁填充率可能會從1/2-15/16,當fill factor(填充因子)小於1/2時,會開始收縮數據頁,釋放空閑空間
4、5.6開始修改page size,支持4k、8k、16k、初始化時指定,后續無法修改,不同page size的實例間也不能直接遷移使用.5.7開始擴展到32kb、64kb。
5、innodb表為IOT,采用了B+樹類型,故每個頁面至少存儲2行數據,如果行過大則會產生溢出;
6、理論上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字節.
7、當file format為Antelope時,支持:REDUNDANT、COMPACT這兩種行格式.發生行溢出時,在當前page會存儲前768字節,多余的放在off-page.
8、當file format為Barracuda時,支持:compress,dynamic這兩種格式,並兼容前兩種,在當前page會存儲前20字節,多余的放在off-page.
9、在多版本方式下,當你使用SQL語句刪除某一行的時候,該行並不會馬上從數據的物理文件上移除.只有當Innodb能夠刪除掉更新日志記錄的時候,那些行及其對應的索引記錄才會真正從物理上刪除掉.這個移除操作稱為purge

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這兩種行格式,並且兼容前兩種

【重點】關於Innodb行格式的選擇
1、compact格式消耗磁盤空間和備份耗時最下,redundant相比之下略大一些.建議采用默認compact格式,適用於絕大數場景;
2、dynamic及compressed格式下.大字段數據存儲在off-page中,如果不需要讀取大字段效率較高,否則效率很差.因此count(*)之類的操作相對快,但進行備份需要全表掃描時,其代價反而更高;適用於很多大字段但無需經常被更新且備份的表.

 

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

四、回收表空間
1、共享表空間無法在線回收,共享表空間想要回收的話,需要全部Innodb導出、刪除、導入,數據表空間用上面方法即可,或者直接清空不需要保存的歷史表,臨時表 truncate table


五、Checkpoint
1、innodb會批量的把buffer pool中的臟頁以及redo log 刷新到磁盤,稱之為檢查點.
2、並不是在一次刷新中刷新所有的內容,因為這樣會降低mysql的性能,甚至無法提供服務
3、在恢復的過程中,innodb會向前掃描實務日志,把這些臟數據刷新到磁盤中
4、innodb循環使用它的事務日志,所以舊的日志必然在未來某一時刻被覆蓋,innodb必須保證,在舊日志被覆蓋之前,與這些舊日志條目相關的臟數據都被刷新到了磁盤
5、如果這一點不能保證,萬一服務器crash,buffer pool中的臟頁就永遠也無法恢復了.
6、所以在切換日志的時候,innodb必然會做檢查點,把所有的臟頁都刷新到磁盤
7、從這個意義上,innodb的事物日志越大,節省的磁盤IO越多,對系統性能越好.但是crash后恢復的時間肯定會變長
8、innodb的檢查點每隔幾秒鍾就會做一次
9、只是經過日志切換后,在日志被沖用前,該日志的內容必須被全部刷新到磁盤,否則系統就會hung住
10、嘗試用大一點的事務日志,可以減少檢查點過程中寫磁盤的次數(之所以節省,是因為IO的合並)


Checkpoint觸發條件
1、每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。
2、每10秒,若buffer pool中的臟頁比率超過了70%,flush PCT_IO(100)的dirty pages,若buffer pool中的臟頁比率未超過70%,flush PCT_IO(10%)的dirty pages = 20;每10s,必定調用一次log_checkpoint,做一次checkpoint

臟頁比率 = 需要被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個)
1、master thread(1個)
2、lock monitor thread(1個)
3、error monitor thread(1個)
4、log thread(1個)
5、read/write thread(8個,默認各4個)
6、purge thread(1個)
7、page cleaner thread(1個)

 

如下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源碼中還采用了其他的方法來盡量保證這個頻率.
@每秒一次操作包括:
1、日志緩沖(log buffer)刷新到磁盤,即使這個事務還沒有提交(總是)
2、合並插入緩沖(insert buffer)可能
3、之多刷新100個innodb的緩沖池(buffer pool)中的臟頁(dirty page)到磁盤(可能)
4、如果當前沒有用戶活動,切刀background loop(可能)

@每10秒操作包括:
1、刷新100個臟頁到磁盤(可能)
2、合並之多5個插入緩沖(總是)
3、將日志緩沖刷新到磁盤(總是)
4、刪除無用undo頁(總是)
5、刷新100個或者10個臟頁到磁盤(總是)
6、產生一個檢查點(總是)

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM