MySQL的I/O性能受實例硬件層存儲介質(普通IO,高IO,超高IO云盤,本地SSD等)、和業務層具體SQL語句(掃描或修改數據量)的影響。
InnoDB I/O系統介紹
為了管理磁盤文件的讀寫操作,InnoDB設計了一套文件IO操作接口,提供了同步IO和異步IO兩種文件讀寫方式,通過一套獨立的I/O系統來處理數據頁的讀取和寫入,如果SQL請求的數據頁不在Buffer Pool中,會產生物理I/O,需要讀寫文件系統存儲的數據:
-
讀數據頁操作
通常用戶線程觸發的數據塊請求讀是同步讀,通過同步I/O實現,同步I/O調用底層的讀接口。
-
寫數據頁操作
寫數據頁默認受double write buffer保護,因此對double write buffer的寫磁盤為同步寫,而對數據文件的寫入為異步寫。通過異步I/O實現,例如后臺線程刷新臟頁,后臺I/O線程會異步的將臟頁刷到磁盤。
除了對普通數據文件的讀寫I/O操作,寫Redo日志、寫Undo日志、寫Binlog日志、排序磁盤臨時表、重建DDL表空間等也會造成大量I/O。
高吞吐導致實例I/O高
- 現象
如果業務并發大,TPS/QPS很高,表中又有很多索引或大字段,頻繁地更新、刪除、插入,讀取數據和刷新臟頁時會有大量的I/O。
您可以在實例監控指標頁面查看讀寫負載情況。
- 解決方案
建議修改當前實例參數降低磁盤讀寫頻率、優化刷新臟頁相關的參數或升級實例規格來解決高吞吐問題。MySQL刷新臟頁策略主要由以下等參數控制:
innodb_max_dirty_pages_pct:緩沖池中允許的臟頁百分比,默認值是75,當臟頁所占百分比超過這個值,innoDB就會進行寫操作以把頁中的已更新數據寫入到磁盤文件中,增加innodb_max_dirty_pages_pct會降低寫操作,節省部分IO。
innodb_io_capacity:設置InnoDB后臺任務每秒執行的I/O操作數的上限,影響刷新臟頁和寫入緩沖池的速率,在磁盤I/O性能不足時,如果參數值過大就會造成I/O阻塞,并且造成InnoDB引擎性能較大的降低,不同磁盤類型默認值不同。
innodb_io_capacity_max:如果刷臟操作過于落后,超過緩沖池中允許的臟頁最大百分比,InnoDB可以超過innodb_io_capacity的限制進行刷新,但是不能超過本參數的值。
如果調節后,查看監控項IO使用率任然保持較高,建議擴容實例內存或者升級實例為高IOPS磁盤類型。
臨時表導致實例I/O高
- 現象
通常情況下MySQL產生的臨時文件很小,同時也會及時釋放,但是一些異常情況下,比如慢查詢,會導致短時間產生大量的臨時文件。如果臨時目錄很大,可能存在慢SQL排序、去重等操作導致創建很大的臨時表。臨時表寫入也會造成I/O增加。您可以在實例監控指標頁面查看臨時表創建情況。
- 解決方案
在控制臺的慢日志頁面,下載并查看執行緩慢的SQL,通過分析慢SQL的執行耗時和執行計劃,優化對應的SQL。
讀取冷數據導致實例I/O高
-
現象
關系型數據庫MySQL版采用的是buffer pool緩存架構,SQL訪問或者修改的數據行,不在buffer pool中命中,就需要到文件系統中讀取物理文件,這時會產生大量的讀IO,如果buffer pool空閑頁不夠,還需要交換部分臟頁數據到磁盤,同時又會產生大量的寫IO。您可以在實例監控指標頁面查看緩沖池命中率。
-
解決方案
根據業務場景重新設計業務緩存策略,或者升級實例規格。
大事務寫Binlog導致實例I/O高
-
現象
關系數據庫MySQL版在事務提交時候需要寫binlog,默認binlog日志為行格式,當出現大事務時候,比如一個大表一次delete大量數據,這時候會產生大量的binlog日志,可能達到幾十G甚至更多,binlog文件需要刷盤,造成突然很高的磁盤IO使用率。
-
解決方案
建議盡量將大事務拆分為小事務,避免大事務和降低刷新磁盤頻率。