為什麼linux cp命令不消耗磁碟IO?
作業系統:centos7
測試文件:a.txt 1.2G
監控命令:iostat -xdm 1
The first scene: cp a.txt b.txt #b.txt is not exist
The second scene: cp a.txt b.txt #b.txt is exist
為什麼第一個場景不消耗IO,第二個場景消耗IO?
很可能是在第一次
cp
操作期間數據沒有被刷新到磁碟,但在第二次操作期間。嘗試設置
vm.dirty_background_bytes
為較小的值,例如 1048576 (1 MiB) 以查看是否是這種情況;runsysctl -w vm.dirty_background_bytes=1048576
,然後您的第一個cp
場景應該顯示 I/O。這裡發生了什麼?
除了同步和/或直接 I/O 的情況外,對磁碟的寫入會在記憶體中緩衝,直到達到門檻值,此時它們開始在後台刷新到磁碟。這個門檻值沒有正式的名稱,但它是由
vm.dirty_background_bytes
和控制的vm.dirty_background_ratio
,所以我稱之為“臟背景門檻值”。從核心文件:
vm.dirty_background_bytes
包含後台核心刷新執行緒將開始寫回的髒記憶體量。
注:
dirty_background_bytes
是 的對應物dirty_background_ratio
。一次只能指定其中一個。當寫入一個 sysctl 時,會立即考慮評估臟記憶體限制,而另一個在讀取時顯示為 0。
dirty_background_ratio
包含,作為包含空閒頁面和可回收頁面的總可用記憶體的百分比,後台核心刷新執行緒將開始寫出臟數據的頁面數。
總可用記憶體不等於總系統記憶體。
vm.dirty_bytes
和vm.dirty_ratio
除了這個,還有第二個門檻。嗯,更多的是限製而不是門檻值,它由
vm.dirty_bytes
和控制vm.dirty_ratio
。同樣,它沒有正式名稱,因此我們將其稱為“臟限制”。一旦“寫入”了足夠多的數據,但沒有送出到底層塊設備,進一步的嘗試write
將不得不等待寫入 I/O 完成。(我不清楚他們必須等待哪些數據的確切細節,可能是 I/O 調度程序的一個功能。我不知道。)為什麼?
磁碟很慢。Spinning rust 尤其如此,因此當磁碟上的 R/W 磁頭移動以滿足讀取請求時,在讀取請求完成並且可以啟動寫入請求之前,無法處理寫入請求。(反之亦然)
效率
這就是為什麼我們在記憶體中緩衝寫請求並記憶體我們讀取的數據的原因;我們將工作從慢速磁碟轉移到更快的記憶體。當我們最終將數據送出到磁碟時,我們有大量的數據可供使用,我們可以嘗試以最小化尋軌時間的方式編寫它。(如果您使用的是 SSD,請將磁碟尋軌時間的概念替換為重新刷新 SSD 塊;重新刷新會消耗 SSD 壽命並且是一個緩慢的操作,SSD 嘗試(以不同程度的成功)用自己的寫入來隱藏記憶體。)
vm.dirty_background_bytes
我們可以調整在核心嘗試使用和將數據寫入磁碟之前緩衝了多少數據vm.dirty_background_ratio
。緩衝的寫入數據過多!
如果您正在寫入的數據量對於它到達磁碟的速度來說太大了,那麼您最終會消耗掉所有的系統記憶體。首先,您的讀取記憶體將消失,這意味著更少的讀取請求將由記憶體提供服務,而必須從磁碟提供服務,從而進一步減慢您的寫入速度!如果你的寫壓力仍然沒有減輕,最終像記憶體分配將不得不等待你的寫記憶體被釋放一些,這將更具破壞性。
所以我們有
vm.dirty_bytes
(和vm.dirty_ratio
);它讓我們說,“嘿,等一下,我們真的是時候把數據放到磁碟上了,以免情況變得更糟。”數據還是太多
但是,硬停止 I/O 是非常具有破壞性的。從讀取程序的角度來看,磁碟已經很慢了,刷新數據可能需要幾秒鐘到幾分鐘的時間;考慮
vm.dirty_bytes
20 的預設值。如果您的系統具有 16GiB 的 RAM 並且沒有交換,您可能會在等待 3.4GiB 的數據刷新到磁碟時發現您的 I/O 阻塞。在具有 128GiB RAM 的伺服器上?當您等待 27.5GiB 數據時,服務將超時!所以保持
vm.dirty_bytes
(或者vm.dirty_ratio
,如果你願意的話)相當低是有幫助的,這樣如果你達到這個硬門檻值,它只會對你的服務造成最小的破壞。什麼是好的價值觀?
使用這些可調參數,您總是在吞吐量和延遲之間進行權衡。緩衝太多,您將獲得很高的吞吐量,但延遲很糟糕。緩衝區太少,你的吞吐量會很糟糕,但延遲會很大。
在只有單個磁碟的工作站和筆記型電腦上,我喜歡設置
vm.dirty_background_bytes
為 1MiB 左右,以及 8MiBvm.dirty_bytes
到 16MiB 之間。對於單使用者系統,我很少發現超過 16MiB 的吞吐量優勢,但是對於任何同步工作負載(如 Web 瀏覽器數據儲存)來說,延遲掛起可能會變得非常糟糕。在任何帶有條帶奇偶校驗數組的東西上,我發現數組條頻寬度的倍數是 ; 的一個很好的起始值
vm.dirty_background_bytes
。它降低了在更新奇偶校驗時需要執行讀/更新/寫序列的可能性,從而提高了陣列吞吐量。對於
vm.dirty_bytes
,這取決於您的服務可能遭受多少延遲。我自己,我喜歡計算塊設備的理論吞吐量,用它來計算它可以在 100 毫秒左右移動多少數據,並進行vm.dirty_bytes
相應的設置。100 毫秒的延遲是巨大的,但它不是災難性的(在我的環境中。)不過,所有這些都取決於您的環境;這些只是尋找適合您的方法的起點。