聊一聊被眾人誤解許久的 iowait

帶你聊技術發表於2023-05-18

來源:PostgreSQL學徒

1瞭解 Linux IOWait

我見過許多 Linux 效能工程師將 CPU 使用率中的 "IOWait" 部分看作是表明系統何時受到 I/O 限制

的東西。在這篇部落格中,我將解釋為什麼這種方法不可靠以及可以使用哪些更好的指標。

讓我們從執行一個小實驗開始——在系統上產生大量的 I/O 使用:

sysbench  --threads=8 --time=0 --max-requests=0  fileio --file-num=1 --file-total-size=10G --file-io-mode=sync --file-extra-flags=direct --file-test-mode=rndrd run

Percona 監控和管理 (PMM) 中的 CPU 使用情況:

聊一聊被眾人誤解許久的 iowait

root@iotest:~# vmstat 10
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 3  6      0 7137152  26452 762972    0    0 40500  1714 2519 4693  1  6 55 35  3
 2  8      0 7138100  26476 762964    0    0 344971    17 20059 37865  3 13  7 73  5
 0  8      0 7139160  26500 763016    0    0 347448    37 20599 37935  4 17  5 72  3
 2  7      0 7139736  26524 762968    0    0 334730    14 19190 36256  3 15  4 71  6
 4  4      0 7139484  26536 762900    0    0 253995     6 15230 27934  2 11  6 77  4
 0  7      0 7139484  26536 762900    0    0 350854     6 20777 38345  2 13  3 77  5

到目前為止,一切順利,而且——我們看到 I/O 密集型工作負載明顯對應於高 IOWait(vmstat 中的 "wa" 列)。

讓我們繼續執行我們的 I/O 密集型工作負載並新增一個繁重的 CPU 密集型工作負載:

sysbench --threads=8 --time=0 cpu run

聊一聊被眾人誤解許久的 iowait

root@iotest:~# vmstat 10
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
12  4      0 7121640  26832 763476    0    0 48034  1460 2895 5443  6  7 47 37  3
13  3      0 7120416  26856 763464    0    0 256464    14 12404 25937 69 15  0  0 16
 8  8      0 7121020  26880 763496    0    0 325789    16 15788 33383 85 15  0  0  0
10  6      0 7121464  26904 763460    0    0 322954    33 16025 33461 83 15  0  0  1
 9  7      0 7123592  26928 763524    0    0 336794    14 16772 34907 85 15  0  0  1
13  3      0 7124132  26940 763556    0    0 386384    10 17704 38679 84 16  0  0  0
 9  7      0 7128252  26964 763604    0    0 356198    13 16303 35275 84 15  0  0  0
 9  7      0 7128052  26988 763584    0    0 324723    14 13905 30898 80 15  0  0  5
10  6      0 7122020  27012 763584    0    0 380429    16 16770 37079 81 18  0  0  1

發生了什麼?IOWait 完全消失了,現在這個系統看起來完全不受 I/O 限制了!

當然,實際上,我們的第一個工作負載沒有任何變化——它仍然是 I/O 密集型的;當我們檢視 "IOWait" 時,它就變得不可見了!

要理解發生了什麼,我們真的需要了解 "IOWait" 是什麼以及它是如何計算的。

有一篇很好的文章(譯文在後面)對這個主題進行了更詳細的介紹,但基本上,"IOWait" 是一種空閒 CPU 時間。如果 CPU 核心因為沒有工作要做而空閒,則該時間被計為 "idle"。但是,如果它因為某個程式在磁碟上等待而空閒,則 I/O 時間將計入"IOWait"。

但是,如果一個程式正在等待磁碟 I/O 但系統上的其他程式可以使用 CPU,則該時間將作為使用者態/系統態時間計入到它們的 CPU 使用率。

由於這種計算方式,其他有趣的行為是可能的。現在我們不再執行八個 I/O 密集型執行緒,而是在四核 VM 上執行一個 I/O 密集型程式:

sysbench  --threads=1 --time=0 --max-requests=0  fileio --file-num=1 --file-total-size=10G --file-io-mode=sync --file-extra-flags=direct --file-test-mode=rndrd run

聊一聊被眾人誤解許久的 iowait

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 3  1      0 7130308  27704 763592    0    0 62000    12 4503 8577  3  5 69 20  3
 2  1      0 7127144  27728 763592    0    0 67098    14 4810 9253  2  5 70 20  2
 2  1      0 7128448  27752 763592    0    0 72760    15 5179 9946  2  5 72 20  1
 4  0      0 7133068  27776 763588    0    0 69566    29 4953 9562  2  5 72 21  1
 2  1      0 7131328  27800 763576    0    0 67501    15 4793 9276  2  5 72 20  1
 2  0      0 7128136  27824 763592    0    0 59461    15 4316 8272  2  5 71 20  3
 3  1      0 7129712  27848 763592    0    0 64139    13 4628 8854  2  5 70 20  3
 2  0      0 7128984  27872 763592    0    0 71027    18 5068 9718  2  6 71 20  1
 1  0      0 7128232  27884 763592    0    0 69779    12 4967 9549  2  5 71 20  1
 5  0      0 7128504  27908 763592    0    0 66419    18 4767 9139  2  5 71 20  1

儘管這個程式完全是 I/O 密集型的,但我們可以看到 IOWait (wa) 不是特別高,不到 25%。在具有 32、64 或更多核心的大型系統上,這種完全出現 IO 瓶頸的程式幾乎是不可見的,會產生個位數的 IOWait 百分比。

因此,高 IOWait 表明系統中有許多程式在等待磁碟 I/O,但即使 IOWait 低,磁碟 I/O 也可能成為系統上某些程式的瓶頸。

如果 IOWait 不可靠,你可以使用什麼來提供更好的可見性?

首先,看一下特定應用的可觀察性。應用程式,如果它被很好地檢測,往往最清楚什麼時候它被磁碟約束,以及什麼特定的任務被 I/O約束。

如果你只能訪問 Linux 指標,請檢視 vmstat 中的 "b"列,它對應於磁碟 I/O 上阻塞的程式。這將顯示此類程式,即使是併發的 CPU 密集型負載,也會遮蔽 IOWait:

聊一聊被眾人誤解許久的 iowait

聊一聊被眾人誤解許久的 iowait

最後,你可以檢視每個程式的統計資訊以瞭解哪些程式正在等待磁碟 I/O。

以上譯自 https://www.percona.com/blog/understanding-linux-iowait/

2什麼是 iowait 以及它如何影響 Linux 效能

I/O 等待或者 iowait、wait、wa、%iowait 或 wait% 通常由 top、sar、atop 等 Linux 命令列系統監控工具顯示。就其本身而言,它是讓我們深入窺探 Linux 系統效能的眾多效能統計資料之一。

最近與一位新客戶的交談中提到了 I/O 等待。在我們的支援電話中,他們報告說他們的 32 CPU 核心系統上的負載峰值為 60 到 80。這導致了頁面載入緩慢、超時和間歇性中斷。原因呢?儲存 I/O 瓶頸最初是由持續高的 iowait 所表示,後來透過額外調查得到證實。

什麼是 I/O 等待?I/O 等待是如何影響 Linux 伺服器效能的?我們如何監控和減少與 I/O 等待相關的問題?繼續閱讀以尋找這些問題的答案。

聊一聊被眾人誤解許久的 iowait

3什麼是 I/O 等待?

I/O 等待適用於 Unix 和所有基於 Unix 的系統,包括 macOS、FreeBSD、Solaris 和 Linux。

I/O 等待 (iowait) 是 CPU(或多個 CPU)空閒的時間百分比,在此期間系統有待處理的磁碟 I/O 請求。(來源:man sar)top man 手冊頁給出了這個簡單的解釋:"I/O 等待 = 等待 I/O 完成的時間。" 換句話說,I/O 等待的存在告訴我們系統空閒時它可以處理未完成的請求。

"iowait shows the percentage of time that the CPU or CPUs were idle during which the system had an outstanding disk I/O request." –  iostat man page.

在使用 Linux top 和其他工具時,你會注意到 CPU(及其核心)在以下狀態下執行:us(使用者態)、sy(核心態)、id(空閒)、ni(nice)、si(軟中斷)、hi(硬中斷)、st(steal)和 wa(等待)。其中,使用者態、核心態、空閒狀態和等待狀態的值加起來應為 100%。請注意,"idle"  和 "wait" 是不同的。"idle" CPU 表示沒有工作負載存在,而另一方面,"wait" (iowait) 表示 CPU 何時處於空閒狀態等待未完成的請求。

如果 CPU 空閒,核心將確定任何來自 CPU 的未完成 I/O 請求(比如 SSD 或 NFS)。如果有,則 "iowait" 計數器遞增。如果沒有任何待處理的請求,則 "idle" 計數器會增加。

4I/O 等待和 Linux 伺服器效能

值得注意的是, iowait 有時可以指示吞吐量瓶頸,而在其他時候,iowait 可能完全沒有意義。有可能擁有高 iowait 的健康系統,但也可能有完全沒有 iowait 的存在瓶頸的系統。

I/O 等待只是 CPU / CPU 核心的指示狀態之一。高 iowait 意味著你的 CPU 正在等待請求,但你需要進一步調查以確認來源和影響。

例如,伺服器儲存(SSD、NVMe、NFS 等)幾乎總是比 CPU 效能慢。因此,I/O 等待可能會產生誤導,尤其是涉及到隨機讀/寫工作負載時。這是因為 iowait 僅測量 CPU 效能,而不測量儲存 I/O。

雖然 iowait 表明 CPU 可以處理更多的工作負載,但根據伺服器的工作負載以及負載如何執行計算或使用儲存 I/O,並不總是可以解決 I/O 等待。或者實現接近於零的值是不可行的。

根據終端使用者體驗、資料庫查詢健康狀況、事務吞吐量和整體應用程式健康狀況,你必須決定報告的 iowait 是否表明 Linux 系統效能不佳。

例如,如果你看到 1% 到 4% 的低 iowait,然後將 CPU 升到 2 倍的效能,iowait 也會增加。具有相同儲存效能的 2 倍更快的 CPU = ~ 2 倍的等待時間。你需要考慮你的工作負載來確定應該首先關注哪些硬體。

5監控和減少 I/O 等待相關問題

聊一聊被眾人誤解許久的 iowait

讓我們看看一些用於監視 Linux 上的 I/O 等待的有價值的工具。

  • atop – 使用 -d 選項執行它或按 d 切換磁碟統計檢視。
  • iostat – 嘗試使用 -xm 2 選項進行擴充套件統計,以兆位元組為單位,以兩秒為間隔。
  • iotop – 類似 top 的 I/O 監視器。嘗試使用 -oPa 選項來僅顯示活動程式的累積 I/O。
  • ps – 使用 auxf,那麼在"STAT"列下,"D"通常表示磁碟 iowait。
  • strace - 檢視程式執行的實際操作。參閱 strace man 手冊。
  • lsof – 確定你負責的程式後,使用 -p [PID] 查詢特定檔案。

減少 I/O 等待相關問題

採取以下步驟減少與 I/O 等待相關的問題。

  • 最佳化應用程式的程式碼和資料庫查詢。這可以大大降低磁碟讀/寫的頻率。這應該是你的第一個方法,因為應用程式越高效,在硬體上的長期花費就越少。另請參閱:100 應用程式效能監控 (APM) 和可觀察性解決方案。
  • 使 Linux 系統和軟體版本保持最新。這不僅對安全性更好,而且通常情況下,最新支援的版本會提供顯著的效能改進,無論是 Nginx、Node.js、PHP、Python 還是 MySQL。
  • 確保有空閒的可用記憶體。足夠的空閒記憶體,以便大約一半的伺服器記憶體用於記憶體緩衝區和快取,而不是交換和換頁到磁碟。當然,這個比例會因情況而異。因此,請確保你沒有交換,並且核心快取壓力不會因缺少可用記憶體而變高。
  • 調整系統、儲存裝置和 Linux 核心以提高儲存效能和使用壽命。
  • 最後,如果一切都失敗了:將儲存裝置升級到更快的 SSD、NVMe 或其他高吞吐量儲存裝置。

6結論

iowait 統計資料是一個有用的效能統計資料,可用於監控 CPU 利用率健康狀況。當 CPU 空閒並且可以執行更多計算時,它會通知系統管理員。然後,我們可以使用可觀察性、基準測試和跟蹤工具(例如上面列出的那些工具)來綜合瞭解系統的整體 I/O 效能。你的主要目標應該是消除因等待磁碟、NFS 或其他與儲存相關的 I/O 而直接導致的任何 iowait。

以上譯自

7小結

這篇文章是今天上午老闆在群裡分享的,我看到後十分有感觸,因為我之前閱讀過類似的文章,知曉 iowait 這個引數的坑,Linux 中的解釋是

Show the percentage of time that the CPU or CPUs were idle during which the system had an outstanding disk I/O request.

也就是說 CPU 在等待磁碟 I/O 請求時,處於空閒狀態的時間百分比(此時正在執行著 idle 程式,空閒的時候也會執行一個程式)。

可以看出,如果系統處於 iowait 狀態,那麼必須滿足以下兩個條件:

  1. 系統中存在等待 I/O 請求完成的程式。
  2. 系統當前正處於空閒狀態,也就是說沒有可執行的程式。

主要程式碼流程如下

void account_process_tick(struct task_struct *p, int user_tick)
{
    cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy);
    struct rq *rq = this_rq();

    // 1. 如果當前程式處於使用者態,那麼增加使用者態的CPU時間
    if (user_tick) {
        account_user_time(p, cputime_one_jiffy, one_jiffy_scaled);
    }
    // 2. 如果前程式處於核心態,並且不是idle程式,那麼增加核心態CPU時間
    else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET)) {
        account_system_time(p, HARDIRQ_OFFSET, cputime_one_jiffy,
                            one_jiffy_scaled);
    }
    // 3. 如果當前程式是idle程式,那麼呼叫account_idle_time()函式進行處理
    else {
        account_idle_time(cputime_one_jiffy);
    }
}

void account_idle_time(cputime_t cputime)
{
    struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
    cputime64_t cputime64 = cputime_to_cputime64(cputime);
    struct rq *rq = this_rq();

    // 1. 如果當前有程式在等待IO請求的話,那麼增加iowait的時間
    if (atomic_read(&rq->nr_iowait) > 0) {
        cpustat->iowait = cputime64_add(cpustat->iowait, cputime64);
    }
    // 2. 否則增加idle的時間
    else {
        cpustat->idle = cputime64_add(cpustat->idle, cputime64);
    }
}

也就是說:

  1. 如果當前有程式在等待 I/O 請求的話,那麼增加 iowait 的時間。
  2. 如果當前沒有程式在等待 I/O 請求的話,那麼增加 idle 的時間。

所以正確解釋是:有程式在等待 IO,被阻塞了,並且當前系統是空閒的,沒有其他程式在執行。

怎麼樣?各位是不是漲知識了?又比如經常被用來判斷磁碟飽和度的 %util 指標,各位可能會在不少文章中看到類似結論:

如果 %util 接近 100%,說明產生的I/O請求太多,I/O系統已經滿負荷,該磁碟可能存在瓶頸。

這個結論也是不嚴謹的,%util 表示該裝置有I/O(即非空閒)的時間比率,不考慮 I/O 有多少,只考慮有沒有。由於現代硬碟裝置都有並行處理多個 I/O 請求的能力,所以 %util 即使達到 100% 也不意味著裝置飽和了。舉個簡化的例子:某硬碟處理單個 I/O 需要0.1秒,有能力同時處理 10 個I/O 請求,那麼當 10 個 I/O 請求依次順序提交的時候,需要 1 秒才能全部完成,在 1 秒的取樣週期裡 %util 達到 100%;而如果 10 個 I/O 請求一次性提交的話,0.1 秒就全部完成,在 1 秒的取樣週期裡 %util 只有 10% 。可見,即使 %util 高達 100%,硬碟也仍然有可能還有餘力處理更多的 I/O 請求,即沒有達到飽和狀態。很可惜,iostat 並沒有用來判斷飽和度的指標。

所以,閱讀此文後,千萬不要再憑藉看到一個 iowait 高指標就判斷 IO 瓶頸了。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024922/viewspace-2952994/,如需轉載,請註明出處,否則將追究法律責任。

相關文章