Innodb Read IO 相關參數源代碼解析


前言:最近在閱讀Innodb IO相關部分的源代碼。在閱讀之前一直有個疑問,show global status 中有兩個指標innodb_data_reads 和 innodb_data_read。兩個計數器僅差一個字母,他們之間的含義到底有何差別呢?本文將通過解析這兩個參數的含義,分析Innodb對於磁盤IO相關的一些知識

 首先我們來看下MySQL官方文檔里對於這兩個參數的解釋:

 文檔對於這兩個參數的解釋非常曖昧。這里的讀是指什么?是從哪里讀?磁盤還是內存?甚至連計數器的單位也不知道。

 

詳細解析:

接下來我們從源代碼來解析這兩個參數。在src/Srv0srv.c中存在對這兩個參數和代碼變量的映射關系的定義代碼,如下:

     export_vars.innodb_data_read = srv_data_read;
     export_vars.innodb_data_reads = os_n_file_reads; 

接着讓我們來看下這兩個代碼變量在哪里進行了累加操作。

srv_data_read 盡有一處代碼進行累加操作,buf0file.c 的 _fil_io 函數中,操作如下:
  srv_data_read+= len;
從這行可以看出,innodb_data_read中實際存的是從磁盤上進行物理IO的字節數。
 
os_n_file_reads 也幾乎只有一處代碼進行累加(其他是windows的sync讀這里忽略),在buf0file.c 的 中,操作如下: os_file_pread

  os_n_file_reads++;

隨后,代碼即調用os_aio_array_reserve_slot將IO請求推入 simulated array,再根據wake_later標志位決定是否調用

os_aio_simulated_wake_handler_thread來立即喚醒IO工作隊列。從這里也可以看到,innodb_data_reads記錄的是innodb對於磁盤發起的讀IO請求次數。
看到這里我們就很容易產生一個疑問: 既然兩個變量都是對磁盤發起的IO的計數器,為什么不直接放在一個函數的相鄰行里呢?

回答這個問題,我們就需要對於innodb的simulated-aio和read-ahead算法有一定理解了。

進入到simulated的aio slot array的請求會有兩種,一種是通過buf_read_page 過來的普通頁的讀請求,一種是通過buf_read_ahead_random/linear 過來的預讀請求。從innodb的實現來說普通數據頁的請求是需要立即返回響應的,所以是同步(sync)IO。而對於預讀這樣數據並非SQL所需要,僅是用於提升性能的頁讀取,這樣的IO完全是可以異步的。這兩個差異也是導致simulated aio出現的原因。把IO請求推入slot array后,數據頁同步請求立即通知worker thread去os做同步IO。而預讀IO請求會不斷的推入slot array直到一次預讀所需要的page全部推入slot中,然后再會通知worker thread。此外在worker thread中,也會判斷一個segment的io請求是否相鄰連續,如果連續則把這些請求合並后,作為一次OS IO發到下層存儲中。

明白了這些也就不難理解為什么計數器要分開在不同的函數中計數了。如果累加都放在 _fil_io中進行,那么 innodb_data_read = 16K * innodb_data_reads (這里假設page沒有做壓縮)。然而在有了異步IO合並這個操作后,實際的innodb_data_reads會少於_fil_io中獲得的計數次數。所以,通過 innodb_data_read / innodb_data_reads得到的比值也可以推斷出一個MySQL實例中順序IO或者可順序預讀的IO比例。

我們在production環境的服務器上做一個驗證:

服務器A:在線用戶訪問的數據庫,猜測隨機IO較多

SHOW GLOBAL STATUS LIKE '%innodb_data_read%';

Innodb_data_read 46384854470656
Innodb_data_reads 2812101578

每次IO平均讀取字節數=16494

服務器B:歷史數據統計的數據庫,數據內容和服務器A完全一樣,猜測順序IO較多

SHOW GLOBAL STATUS LIKE '%innodb_data_read%';

Innodb_data_read 54835669766144
Innodb_data_reads 2604758776

每次IO平均讀取字節數=21052

可見順序IO較多的MySQL的單次IO讀取字節數確實要多於一個page的大小,說明IO合並效果明顯。

而隨機IO較多的MySQL的單詞IO讀取字節數幾乎和一個page大小一致,即16K

 

最后我們再總結下一些結論:

  • Innodb_data_read   表示Innodb啟動后,從物理磁盤上讀取的字節數總和。
  • Innodb_data_reads 表示Innodb啟動后,隊伍物理磁盤發起的IO請求次數總和。
  • Innodb_data_read / Innodb_data_reads 得到的比值,越接近16K說明IO壓力越傾向於隨機IO,越遠離16K說明IO從順序預讀中獲得性能提升越多

 

 

 

 參考資料:

1. InnoDB異步IO(AIO)實現詳解 http://hedengcheng.com/?p=98

 

 


免責聲明!

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



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