Innodb特性以及實現原理


 

1.insert buffer
2.double write
3.自適應哈希索引
4.異步io
5.鄰接頁刷新

1.insert buffer(change buffer)

作用:將非聚集索引上的DML操作從隨機IO變成順序IO,減少IO次數,提高效率

innodb使用insert buffer"欺騙"數據庫:對於為非唯一索引,輔助索引的修改操作並非實時更新索引的葉子頁,而是把若干對同一頁面的更新緩存起來做合並為一次性更新操作,轉化隨機IO 為順序IO,這樣可以避免隨機IO帶來性能損耗,提高數據庫的寫性能。

 

insert buffer使用的條件:

  • 索引是輔助索引
  • 索引是非唯一索引(如果是唯一索引,每次變更都要判斷索引的唯一性,又產生了離散讀取,使insert buffer失去了意義)

具體查看

show engines inndo status 過濾
   Ibuf: size 1, free list len 14316, seg size 14318(插入緩沖區的總大小 頁的數量X16KB), 466174 merges(已經合並的meregs數量)
   merged operations: insert 547399(插入記錄被merge的次數), delete mark 42008(刪除操作被merge的次數), delete 32055(更新操作被merge了多少次)
   如果merges/merged的值等於3/1,則代表插入緩沖對於非聚集索引頁的IO請求大約降低了3倍

  change buffer

insert buffer的升級版,可以對DML都進行緩沖,insert ,delete,update,他們分別對應:insert buffer,delete buffer,purge buffer

對應參數

innodb_change_buffering:控制開啟哪種buffer,可選值為:inserts,deletes,purgees,changes,all,none.

  •  all:默認值,緩存插入、標記刪除和后台物理清理
  •     none:不緩存任何操作產生的數據
  •     inserts:緩存insert產生的數據
  •     deletes:緩存標記刪除對輔助索引產生的變化
  •     changes:inserts和deletes的合並項
  •     purges:內部物理清除所產生的數據

 

innodb_change_buffer_max_size:控制change buffer最大使用內存數量,默認25(內存的1/4)

 

-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 98, seg size 100, 0 merges
merged operations:具體每個操作的次數
 insert 0, delete mark 0(delete buffer), delete 0 (purge buffer)
discarded operations:當change buffer 發生merge時,表已經唄刪除,此時無需再將記錄合並(merge)到輔助索引了
 insert 0, delete mark 0, delete 0

  insert buffer 的內部實現

insert buffer是一顆B+ 樹,4.1版本后全局只有一個B+樹,存放在ibdata1中

非葉子節點存放的是查詢的search key.

一共9個字節:

  • space:待插入記錄所在表的表空間id,4個字節
  • marker:兼容老版本insert buffer,1個字節
  • offset:頁所在的偏移量,4個字節

1.當插入一條數據,同時要更新輔助索引時,先在緩沖池中找要更新的索引所在的頁,如果找到,直接更新索引,

不在,將操作緩沖到change buffer中>在下次進行操作這個數據頁時,數據頁讀入內存,進行操作數據頁(更新,插入)->寫事務日志

merge insert buffer情況

  • 輔助索引頁被讀入緩沖池
  • insert buffer bitmap頁追蹤到該輔助索引頁已經沒有可用空間
  • master thread調度機制

Master Thread的調度規則 

a 主動merger[innodb主線程定期完成,用戶線程無感知]
    主動merger:
    原理:主動merge通過innodb主線程(svr_master_thread)判斷:若過去1s之內發生的I/O小於系統I/O能力的5%,
        則主動進行一次insert buffer的meger操作。meger的頁面數為系統I/O能力的5%,讀取采用async io模式。
        每10s,必定觸發一次insert buffer meger操作。meger的頁面數仍舊為系統 I/O能力的5%。
    步驟:
        1.主線程發出async io請求,async讀取需要被meger的索引頁面
        2.I/O handler 線程,在接受到完成的async I/O之后,進行merger
  b 被動merge[用戶線程完成,用戶能感受到meger操作帶來的性能影響]
    被動merge:
      情況一:
      insert操作,導致頁面空間不足,需要分裂(split)。由於insert buffer只針對單個頁面,不能buffer page split[頁已經在內存里],因此引起頁面的被動meger。同理,update操作導致頁面空間不 足;purge導致頁面為空等。總之:若 當前操作引起頁面split or merge,那么就會導致被動merge。
      情況二:
      insert操作,由於其它各種原因,insert buffer優化返回false,需要真正讀取page時,要進行被動merge。與一不同的是,頁在disk上,需要讀取到內存里。
      情況三:
      在進行insert buffer操作,發現insert buffer太大,需要壓縮insert buffer,這時需要強制被動merge,不允許 insert 操作進行。

 

2.double write

保障innodb引擎的可靠性

背景

部分寫失效問題(partial page write)

 InnoDB 的Page Size一般是16KB,其數據校驗也是針對這16KB來計算的,將數據寫入到磁盤是以Page為單位進行操作的。而計算機硬件和操作系統,在極端情況下(比如斷電)往往並不能保證這一操作的原子性,16K的數據,寫入4K 時,發生了系統斷電/os crash ,只有一部分寫是成功的,這種情況下就是 partial page write 問題。
很多DBA 會想到系統恢復后,MySQL 可以根據redolog 進行恢復,而mysql在恢復的過程中是檢查page的checksum,checksum就是pgae的最后事務號,發生partial page write 問題時,page已經損壞,找不到該page中的事務號,就無法恢復。

如果想通過redo log恢復業務無法實現的,因為redo log記錄的是對頁的物理操作,如偏移量200寫‘jinhailan’記錄,頁本身發生了損壞,無法進行重做.所以需要維護一個副本,在寫入失效后,可以通過副本來還原該頁在進行重做.

Double write 是InnoDB在 tablespace上的128個頁(2個區)是2MB.

原理:

  為了解決 partial page write 問題 ,當mysql將臟數據flush到data file的時候, 先使用memcopy 將臟數據復制到內存中的double write buffer ,之后通過double write buffer再分2次,每次寫入1MB到共享表空間,然后馬上調用fsync函數,同步到磁盤上,避免緩沖帶來的問題,在這個過程中,doublewrite是順序寫,開銷並不大,在完成doublewrite寫入后,在將double write buffer寫入各表空間文件,這時是離散寫入。
如果發生了極端情況(斷電),InnoDB再次啟動后,發現了一個Page數據已經損壞,那么此時就可以從doublewrite buffer中進行數據恢復了。

 

 

 

doublewrite的缺點是什么?

位於共享表空間上的doublewrite buffer實際上也是一個文件,寫共享表空間會導致系統有更多的fsync操作, 而硬盤的fsync性能因素會降低MySQL的整體性能,但是並不會降低到原來的50%。這主要是因為:

  1. doublewrite是在一個連續的存儲空間, 所以硬盤在寫數據的時候是順序寫,而不是隨機寫,這樣性能更高。
  2. 將數據從doublewrite buffer寫到真正的segment中的時候,系統會自動合並連接空間刷新的方式,每次可以刷新多個pages。
double write在恢復時如何工作

If there’s a partial page write to the doublewrite buffer itself, the original page will still be on disk in its real location.---如果是寫doublewrite buffer本身失敗,那么這些數據不會被寫到磁盤,InnoDB此時會從磁盤載入原始的數據,然后通過InnoDB的事務日志來計算出正確的數據,重新 寫入到doublewrite buffer.

When InnoDB recovers, it will use the original page instead of the corrupted copy in the doublewrite buffer. However, if the doublewrite buffer succeeds and the write to the page’s real location fails, InnoDB will use the copy in the doublewrite buffer during recovery. 
--如果 doublewrite buffer寫成功的話,但是寫磁盤失敗,InnoDB就不用通過事務日志來計算了,而是直接用buffer的數據再寫一遍.
InnoDB knows when a page is corrupt because each page has a checksum at the end; the checksum is the last thing to be written, so if the page’s contents don’t match the checksum, the page is corrupt. Upon recovery, therefore, InnoDB just reads each page in the doublewrite buffer and verifies the checksums. If a page’s checksum is incorrect, it reads the page from its original location.
--在恢復的時候,InnoDB直接比較頁面的checksum,如果不對的話,就從硬盤載入原始數據,再由事務日志 開始推演出正確的數據.所以InnoDB的恢復通常需要較長的時間.

是否一定需要doublewrite
 

在一些情況下可以關閉doublewrite以獲取更高的性能。比如在slave上可以關閉,因為即使出現了partial page write問題,數據還是可以從中繼日志中恢復。設置InnoDB_doublewrite=0即可關閉doublewrite buffer。

如何使用 double write

InnoDB_doublewrite=1表示啟動double write
show status like 'InnoDB_dblwr%'可以查詢double write的使用情況;
相關參數與狀態
Double write的使用情況:
show status like  "%InnoDB_dblwr%";


InnoDB_dblwr_pages_written 從bp flush 到 DBWB的個數
InnoDB_dblwr_writes            寫文件的次數
每次寫操作合並page的個數= InnoDB_dblwr_pages_written/InnoDB_dblwr_writes  

 

 

自適應哈希索引

 Innodb存儲引擎會監控對表上二級索引的查找,如果發現某二級索引被頻繁訪問,二級索引成為熱數據,建立哈希索引可以帶來速度的提升

 

 經常訪問的二級索引數據會自動被生成到hash索引里面去(最近連續被訪問三次的數據),自適應哈希索引通過緩沖池的B+樹構造而來,因此建立的速度很快。

特點

  1、無序,沒有樹高

  2、降低對二級索引樹的頻繁訪問資源

    索引樹高<=4,訪問索引:訪問樹、根節點、葉子節點

  3、自適應

3、缺陷

  1、hash自適應索引會占用innodb buffer pool;

  2、自適應hash索引只適合搜索等值的查詢,如select * from table where index_col='xxx',而對於其他查找類型,如范圍查找,是不能使用的;

  3、極端情況下,自適應hash索引才有比較大的意義,可以降低邏輯讀。

 

限制

  1、只能用於等值比較,例如=, <=>,in

  2、無法用於排序

  3、有沖突可能

  4、MySQL自動管理,人為無法干預。

由於innodb不支持hash索引,但是在某些情況下hash索引的效率很高,於是出現了adaptive hash index功能,但是通過上面的狀態監控,可以計算其收益以及付出,控制該功能開啟與否。

  默認開啟,建議關掉,意義不大。可以通過 set global innodb_adaptive_hash_index=off/on 關閉和打開該功能。

 

 

異步IO

為了提高磁盤操作性能,當前的數據庫系統都采用異步IO的方式來處理磁盤操作。

  1、異步IO:用戶可以在發出一個IO請求后立即再發出另外一個IO請求,當全部IO請求發送完畢后,等待所有IO操作完成,這就是AIO。

  2、與AIO對應的是Sync IO,即每進行一次IO操作,需要等待此次操作結束才能繼續接下來的操作。

 

異步IO的好處  

  1、不用等待直接響應上一個用戶的請求;

  2、多次的請求在一起排序,請求的數據頁是在一起的,一次讀出來,減少多次讀。(數據庫的讀寫請求隊列放在文件系統中單獨分配的一塊小內存結構里,非文件系統的緩存)

 

鄰接頁刷新

 

當刷新一個臟頁時,innodb存儲引擎會檢測該頁所在區(extent)的所有頁,如果是臟頁,那么一起進行刷新。這樣做的好處顯而易見,通過AIO可以將多個IO寫入操作合並為一個IO操作,增大寫入量,減少了物理寫IO,故該工作機制在傳統機械磁盤下有着顯著的優勢。

  1、在寫入次數基本不增加的情況下,增加了寫入的量;

  2、加速了臟頁的回收;

  3、充分利用double write每次1M寫入的特征;

  4、這個功能打開以后會發現iostat里面的wrqm(合並寫)這個值會比較高

 

Flush neighbor page的影響

  1、對於insert頻繁的系統,這個功能比較適合

  2、對於update頻繁的系統,這個功能可能會帶來一些副作用

    1、update順帶着刷新其他頁;

    2、對於update頻繁的表,這些頁馬上就臟了,白白浪費寫負載。

 


免責聲明!

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



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