| 做者 王文安,騰訊CSIG數據庫專項的數據庫工程師,主要負責騰訊雲數據庫 MySQL 的相關的工做,熱愛技術,歡迎留言進行交流。mysql
檢查 IO 的問題會使用iostat這個命令,這裏展現一下命令的效果(iostat -x 1 -m,debian 10.2):linux
iostatios
avg-cpu 天然就是 CPU 相關的指標,判斷 IO 問題時能夠關注 %iowait,其餘指標的意義以下:sql
·r/s 和 w/s:合併事後的讀請求和寫請求的每秒請求數,能夠當作 IOPS 來理解。數據庫
·rMB/s 和 wMB/s:磁盤的讀寫吞吐量。數組
·rrqm/s 和 wrqm/s:每秒合併的讀請求和寫請求數量。緩存
·%rrqm 和 %wrqm:合併的讀請求和寫請求百分比。服務器
·r_await 和 w_await:讀請求和寫請求的平均響應時間,包含真正的處理時間和隊列中的等待時間(ms)。架構
·aqu-sz:平均隊列深度。性能
·rareq_sz 和 wareq_sz:一個讀請求和寫請求的平均物理大小(KB)。
·scvtm:計算出來的平均 IO 響應時間,目前已經不許確,不用再關注。
·%util:若是使用了 RAID 或者 SSD,則忽略這個指標,僅在單塊機械盤上準確。
通常來講,評價一塊 IO 設備(忽略機械盤的狀況,沒有評價的意義)是否達到了高負載狀況,能夠看這幾個指標:r/s,w/s,rMB/s,wMB/s,r_await,w_await,aqu-sz。
因爲 MySQL 涉及到 IO 相關的參數會比較多,所以這裏僅一部分常常用到的參數以及在測試&模擬中使用默認設置:
參數
設置
備註
innodb_io_capacity
16000
定義了後臺任務可用的 IOPS 量
innodb_io_capacity_max
32000
定義了後臺任務可用的最大 IOPS 量
innodb_flush_log_at_trx_commit
1
控制事務的提交策略,具體信息請參考官方文檔
sync_binlog
1
控制 binlog 落盤的頻率,具體信息請參考官方文檔
innodb_io_capacity 和 innodb_io_capacity_max 是最直接限制 IOPS 的指標,大多數時候,SSD 能夠設置成 16000 或者更高的數值,若是是雲主機或者其餘的共享存儲設備,則須要瞭解一下詳細的 IOPS 上限再具體調整。trx_commit 和 sync_binlog 這兩個參數也放進來的緣由是不一樣的參數組合對 IO 的壓力也會有區別。一般的用法是雙 1 或者 20(二零),參考官方文檔的描述,雙 1 在每次提交事務的時候都會刷盤,對 IO 的壓力要高很多;20 則是滯後刷盤,對 IO 的壓力會較小,所以寫入 QPS 會高一些。
另外,能夠關注到一個細節,innodb_io_capacity 的描述對象是:後臺任務。這表明着 MySQL 後臺的 flush,purge 操做會受到這個參數設置的限制。
本次測試使用騰訊雲服務器的高 IO 型 IT3 實例,自帶了 3TB 的本地 NVME。因爲騰訊雲平臺限制了系統版本(debian 9),所以 iostat 在輸出內容上稍有差別,可是不影響分析,簡單用 fio 跑了一下 16k(innodb_page_size 的默認配置) 的 IO 性能:
類型
IOPS
吞吐量(MB)
隨機讀
121959
1905
隨機寫
98326
1536
隨機讀寫(讀部分)
47129
750
隨機讀寫(寫部分)
47152
754
那麼,爲何測試環境要用一個徹底不會有 IO 瓶頸的呢?這是爲了方便展現調整 MySQL 以後的效果。若是整套系統的 IO 設備負載長期處於高水位的話,最佳優化策略是升級 IO 設備,而不是調整 MySQL。所以全部的分析和應對的場景都屬於中、短期內的高 IO 負載。
先看一種比較純粹,可是較少出現的 IO 負載場景:
iostat_wo
這種類型的指標有一個明顯的特色:IO 負載中沒有,或者幾乎沒有讀取相關的壓力。這種負載的特徵通常是緩存足夠放下全部的數據,所以不須要從磁盤上讀數據,壓力所有在寫入上。
首先能想到的,顯然是trx_commit 和 sync_binlog 這兩個參數,把雙 1 改爲 20 的配置,產生 QPS 變化的緣由也比較好理解:本來一個事務須要刷一次磁盤,變成多個事務刷盤操做合併到了一塊兒,就像是提升了每一個 IOPS 的「事務處理效率」,好比從 1 事務/IOPS 變成了 N 事務/IOPS。
除了提升「每一個 IOPS 的事務處理效率」之外,其實還會有另一種思路:適當限制後臺任務的 IOPS。實際上 MySQL 的寫入會涉及到很是多的 buffer,log,併產生後臺任務相關的數據,出現中等時間的高寫入場景時,後臺任務通常會慢慢堆積須要 flush 和 purge 的數據,若是 innodb_io_capacity 和 innodb_io_capacity_max 的參數設置得比較高,可能會讓後臺任務消耗過多的 IO 資源,這時候適當調低一些能夠在一段時間內穩住寫入 QPS,等高寫入的壓力過去以後再回滾設置。
另外,若是有更加精細化的調整方式,應該會有更好的效果,目前只能靠這個參數一刀切,不過不要改得過低,由於當後臺任務堆積的數據過多,觸發強制刷髒/checkpoint 等機制時,會大幅度的侵佔 IO 資源,致使很是劇烈的寫入 QPS 波動,這一點須要注意。
這裏給出「反向調整」的效果,日誌數據取自於某一個 sysbench 客戶端,在 2050s 左右的時候大幅度調高了 io_capacity:
另一種比較純粹的場景,天然就是純讀取了,例如:
iostat_ro
純讀取的 IO 特徵說明緩存不夠大,須要從磁盤讀取熱數據。那麼增長內存和調高 innodb_buffer_pool_size,把更多的數據放到內存中就是最好的解決方案。至於須要加多少內存,能夠結合實際業務 SQL 的響應時間(作好索引優化以後)和 buffer_pool 的命中率,從經驗值來看,命中率(show engine innodb status裏面)高於 99.5% 是比較理想的,若是實際 SQL 的響應時間不知足業務的需求,那麼就能夠根據實際命中率來估算須要的內存大小。
因爲從 5.7 開始,MySQL 支持動態調整 innodb_buffer_pool_size 這個參數了,所以變動帶來的影響相對小了不少,不過調整仍是有代價的,儘可能在業務低峯期操做。
最多見的確定是讀寫混合的場景,好比像這樣子的:
iostat_rw
分析起來會相對複雜一點,可是結合純讀取和純寫入的分析以後,能夠比較容易想到以下的可能性:
場景一:讀寫混合的場景。
場景二:純寫入的場景,可是內存放不下全部的數據,須要從磁盤讀取以後再修改。
先看比較簡單的場景2,本質上仍是相似於純寫入場景,可是因爲內存不夠大,所以在排查 MySQL 的讀寫 SQL 比例(global status 中的 com_xxx 系列數據)以後,能夠參考純寫入這個章節的內容進行分析處理。
雖然場景 1 會複雜一些,可是結合純寫和純讀的內容,分析的思路就有了,好比依次思考以下問題:
業務讀寫比例大概是多少?
IO 系統的讀性能問題比較大仍是寫性能問題比較大?
若是說:
業務讀的比例高(例如 >4:1),IO 系統讀的性能問題比較大:那麼參考純讀取的內容,調高 buffer_pool_size 。
業務讀的比例高(例如 >4:1),IO 系統寫的性能問題比較大:那麼參考純寫入的內容,調整事務提交策略或者 io_capacity。另外,此類場景多是由於在大批量變動數據,也能夠考慮一下優化這種業務行爲。
業務寫的比例高(例如<4:1),IO 系統讀的性能問題比較大:那麼參考純讀取的內容。
業務寫的比例高(例如<4:1),IO 系統寫的性能問題比較大:那麼參考純寫入的內容。
業務的讀寫比例沒有什麼明顯的特色,IO 系統讀寫的性能問題都比較嚴重:考慮以上全部的方法,包括升級硬件。
吞吐量和 IOPS ,通常狀況下衡量 IO 系統性能最直觀的指標,並無特別的說起,主要緣由仍是判斷起來很簡單:若是iostat的指標已經達到或者接近了實際硬件的指標(好比達到了 75%),那麼根據業務量增加的狀況及早規劃硬件升級或者其餘的手段來分散讀寫壓力。
常規的手段,能夠簡單的遵循如下場景來酌情使用:讀多寫少讀寫分離,寫多讀少拆庫拆表加緩存。
若是 MySQL 在 IO 方面出現了阻塞的現象,那麼能夠觀察如下幾個指標:
參數名
意義
備註
Innodb_data_pending_fsyncs
當前阻塞的 fsync 操做
通常爲 0,比較高的話,看一下 innodb_flush_method 的設置
Innodb_data_pending_reads
當前阻塞的 read 操做
通常爲 0,若是指標較高且影響業務的話,參考讀壓力的應對方式
Innodb_data_pending_writes
當前阻塞的 write 操做
通常爲 0,若是指標較高且影響業務的話,參考寫壓力的應對方式
Innodb_os_log_pending_fsyncs
寫 redo log 時,當前阻塞的 fsync 操做
通常爲 0,若是大於 0 的話,一般就是 IO 設備的瓶頸,考慮把 redo log 遷移到 SSD 或者作 IO 隔離,獨佔 IO 設備的性能
Innodb_os_log_pending_writes
寫 redo log 時,當前阻塞的 write 操做
通常爲 0,若是指標較高且影響業務的話,參考寫壓力的應對方式
InnoDB 還有不少其餘的 read 和 write 的指標,經過show global status like '%innodb%read%'之類的操做均可以看到,可是這類指標通常是累計值,須要對比上一個取值時間的差值纔能有比較實際的做用,一般也是用來判斷 MySQL 的讀寫比例用,結合上表的 pending 數據和其餘的系統指標來綜合判斷 IO 系統的負載。這些指標也是建議監控起來的。
解決 IO 問題的手段是多樣化的:最省事的升級硬件;最快捷的調整 MySQL(本文主要內容);比較經常使用的架構調整手段(讀寫分離,拆庫拆表);結合實際狀況來優化業務的行爲(合併單行操做的 DML,拆分單個大量更新數據的 DML 語句等)。
雖然不能對上述手段進行全面的介紹,可是iostat提供的信息在分析 MySQL 瓶頸時仍是很是有用的,本文僅從硬件的負載特色出發,簡述了調整 MySQL 的一些思路。實際上須要多種手段結合起來才能比較好的應對 IO 方面的問題。
本文由博客一文多發平臺 OpenWrite 發佈!