聊一聊被眾人誤解許久的 iowait
來源: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 使用情況:
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
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
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:
最後,你可以檢視每個程式的統計資訊以瞭解哪些程式正在等待磁碟 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 等待相關的問題?繼續閱讀以尋找這些問題的答案。
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 等待相關問題
讓我們看看一些用於監視 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 狀態,那麼必須滿足以下兩個條件:
系統中存在等待 I/O 請求完成的程式。 系統當前正處於空閒狀態,也就是說沒有可執行的程式。
主要程式碼流程如下
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);
}
}
也就是說:
如果當前有程式在等待 I/O 請求的話,那麼增加 iowait 的時間。 如果當前沒有程式在等待 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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 聊一聊chkrookit的誤信和誤用
- 聊一聊Oracle的Tablespace(一)Oracle
- 聊一聊 JVM 的 GCJVMGC
- 聊一聊 RestTemplateREST
- 聊一聊 cookieCookie
- 龍蜥開發者說:眾人拾柴火焰高!聊一聊我在社群的所思所想 | 第 14期
- 聊一聊遊戲的壓測遊戲
- 聊一聊 Javascript 中的 ASTJavaScriptAST
- 聊一聊 TLS/SSLTLS
- 聊一聊Java的列舉enumJava
- 聊一聊Redis的離線分析Redis
- 聊一聊MySQL的字符集MySql
- 聊一聊MySQL的儲存引擎MySql儲存引擎
- 簡單聊一聊Vuex的原理Vue
- 聊一聊Javascript中的Promise物件JavaScriptPromise物件
- 聊一聊MySQL的直方圖MySql直方圖
- 聊一聊前端換膚前端
- 聊一聊Greenplum與PostgreSQLSQL
- 聊一聊模板方法模式模式
- 聊一聊測試流程
- 聊一聊session和cookieSessionCookie
- 聊一聊JWT與sessionJWTSession
- 聊一聊Iterable與Iterator的那些事!
- 聊一聊MySQL索引失效的問題MySql索引
- 聊一聊RocketMQ的註冊中心NameServerMQServer
- 聊一聊 SQLSERVER 的行不能跨頁SQLServer
- 簡單聊一聊FutureTask的實現
- 聊一聊隨機數安全隨機
- 面試官(7): 聊一聊 Babel?面試Babel
- 聊一聊前端業務開發前端
- 面試官:聊一聊索引吧面試索引
- 和手遊開發者聊一聊 iPhoneiPhone
- 聊一聊責任鏈模式模式
- 聊一聊介面卡模式模式
- 聊一聊裝飾者模式模式
- 聊一聊遊戲版本運營遊戲
- 聊一聊系統重構
- 簡單聊一聊ThreadPoolExecutorthread