服務器IO瓶頸對MySQL性能的影響


【背景】

之前我們碰到一些MySQL的性能問題,比如服務器日志備份時可能會導致慢查詢增多,一句簡單的select或insert語句可能執行幾秒,IO負載較高的服務器更容易出現並發線程數升高,CPU上升等問題。

最近學習了MySQL InnoDB IO相關的部分內核原理,可以幫我們了解服務器IO瓶頸對MySQL性能的影響,下面以MySQL5.7.23的源碼為例

【原理】

1、InnoDB實現了同步IO和異步IO兩種文件讀寫方式

(1、)對於讀操作,通常用戶線程觸發的數據請求都是同步讀,其他后台線程觸發的是異步讀。

(2、)對於寫操作,InnoDB是WAL模式,先寫日志,延遲寫數據頁;

redo log的寫操作大部分是異步寫,主要在下面場景下觸發

<1、>redo log buffer空間不足時;

<2、>當參數innodb_flush_log_at_trx_commit設置為1時,每次事務提交都會做一次fsync,相當於是同步寫;

<3、>master線程每秒做一次redo fsync;

<4、>checkpoint

<5、>實例shutdown時

<.6、>binlog切換時

 Page cleaner線程負責臟頁的刷新操作,其中double write buffer的寫磁盤是同步寫,數據文件的寫入是異步寫。

 

2、同步讀寫操作通常由用戶線程來完成,下面先分析同步讀

當用戶線程執行一句SQL時,如果請求的數據頁不在buffer pool中,就需要將文件中的數據頁加載到buffer pool中,

從函數buf_read_page可以看到這里是同步讀操作,如果IO有瓶頸,響應延遲,那么該線程就會被阻塞。

從函數buf_page_init_for_read可以看到,在讀數據頁時會加X鎖

這時如果有其他用戶線程請求相同的數據頁時,從函數buf_wait_for_read看到,嘗試獲取X鎖,就會處於阻塞狀態。

當服務器IO成為瓶頸,發生上面的問題時,就會出現SQL執行變慢

問題進一步惡化,大量慢查詢,運行中的線程處於等待狀態,占用了Innodb線程(innodb_thread_concurrency我們的配置大部分是0或64,實際上通常是CPU的邏輯核數40)

對於並發較高的系統,會導致其他大量的線程處於等待隊列中,並發線程過高又會導致上下文切換頻繁,CPU上升。

 

3、一個同步寫的例子

前面做過一個測試,執行500W條insert語句

用source執行insert腳本,TPS大約在每秒700,后面並行同時執行3個insert腳本,TPS達到每秒2000左右,IO %util已經接近100%

由於此時參數innodb_flush_log_at_trx_commit設置為1時,每次事務提交都會做一次fsync,相當於是同步寫,IO已達到瓶頸,TPS處理能力無法提高。

當將參數innodb_flush_log_at_trx_commit臨時調整為2,改為后台進程進行異步寫,並行執行8個insert腳本,TPS達到每秒約1W左右,IO %util約在8%。

實現邏輯可以關注log_write_up_to函數

 

【應用場景】

1、當服務器IO出現瓶頸,會導致MySQL性能大幅下降,因此建議盡可能的利用服務器內存資源,將實例的innodb_buffer_pool_size設置為物理內存的70%左右;

2、合理的拆分,盡可能的讓一個實例的熱點數據都可以緩存在innodb buffer pool中

3、對於某些場景下執行腳本,或初始化數據時,可以將innodb_flush_log_at_trx_commit臨時設置為2,能大幅提升導入性能。

參考資料:

http://mysql.taobao.org/monthly/2017/03/01/

http://mysql.taobao.org/monthly/2016/02/02/

http://mysql.taobao.org/monthly/2017/07/10/

 


免責聲明!

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



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