1. 程式人生 > >是什麼導致MySQL資料庫伺服器磁碟I/O高? – 運維派

是什麼導致MySQL資料庫伺服器磁碟I/O高? – 運維派

0、導讀

有個MySQL伺服器的磁碟I/O總有過高報警,怎麼回事?

1、問題

我的朋友小明,TA有個MySQL伺服器最近總是報告磁碟I/O非常高,想著我這有免費的不用白不用的企業技術服務(TA自己這麼想的),就找我幫忙給把把脈。

作為一個經驗豐富(踩坑不斷)的DBA,出現這種問題,一般來說,磁碟I/O很高無非是下面幾個原因引起:

磁碟子系統裝置效能差,或採用ext2/ext3之類檔案系統,或採用cfq之類的ioscheduler,所以IOPS提上不去;

SQL效率不高,比如沒有索引,或者一次性讀取大量資料,所以需要更多的I/O;

可用記憶體太小,記憶體中能快取/緩衝的資料不多,所以需要更多的I/O。

方法論已有,接下來就是動手開始排查了。

2、排查

先看磁碟I/O裝置,是由十幾塊SSD組成的RAID10陣列,按理說I/O效能應該不至於太差,看iops和%util的資料也確實如此。

磁碟I/O裝置

再來看下檔案系統、io scheduler的因素,發現採用xfs檔案系統,而且io scheduler用的是noop,看來也不是這個原因。而且看了下iostat的資料,發現iops也不算低,說明I/O能力還是可以的。

檔案系統

再來看看當前的processlist,以及slow query log,也沒發現當前有特別明顯的slow query,所以也不是這個原因了。

processlist

現在只剩下記憶體不足這個因素了,看了下伺服器實體記憶體是64G,用系統命令 free 看了下,發現大部分都在cached,而free的也不多。觀察InnoDB相關的配置以及status,看能不能找到端倪。

首先,看下 innodb-buffer-pool-size 分配了多少:

innodb-buffer-pool-size

嗯,分配了18G,好像不是太多啊~

再看一下 innodb status:

分配

重點關注下幾個wait值,再看下show engine innodb結果:

wait值

關注下unpurge列表大小,看起來還是比較大的(有111萬)。

更為詭異的是,在已經停掉SLAVE IO & SQL執行緒後,發現redo log還在一直增長…

第一次看

SLAVE IO & SQL執行緒

停掉SLAVE執行緒後過陣子再看

SLAVE執行緒

看到這裡,有經驗的DBA應該基本上能想明白了,主要是因為 innodb buffer pool 太小,導致了下面幾個後果:

  1. dirty page 和 data page 之間相互“排擠搶佔”,所以會出現 Innodb_buffer_pool_wait_free 事件;
  2. redo log 也沒辦法及時重新整理到磁碟中,所以在SLAVE執行緒停掉後,能看到LSN還在持續增長;
  3. 同時我們也看到unpurge的列表也積攢到很大(111萬),這導致了ibdata1檔案漲到了146G之大,不過這個可能也是因為有某些事務長時間未提交。

還有,不知道大家注意到沒,Innodb_row_lock_current_waits 的值竟然是 18446744073709551615(想想bigint多大),顯然不可能啊。事實上,這種情況已經碰到過幾次了,明明當前沒有行鎖,這個 status 值卻不小,查了一下官方bug庫,竟然只報告了一例,bug id是#71520。

3、解決

既然知道原因,問題解決起來也就快了,我們主要做了下面幾個調整:

  • 調大innodb-buffer-pool-size,原則上不超過實體記憶體的70%,所以設定為40G;
  • 調大innodb-purge-thread,原來是1,調整成4;
  • 調大innodb_io_capacity和innodb_io_capacity_max,值分別為2萬和2.5萬;

調整完後,重啟例項(5.7版本前調整innodb-buffer-pool-size 和 innodb-purge-thread 需要重啟才生效)。再經觀察,發現IOPS下降的很快,不再告警,同時 Innodb_buffer_pool_wait_free 也一直為 0,unpurge列表降到了數千級別,搞定,收工,繼續搬磚賣茶~

作者:葉金榮

文章出處:老葉茶館(訂閱號ID:iMySQL_WX)