Linux

關於Page Cache和dirty_background_bytes的誤解

  • October 30, 2019

我已經研究了一段時間了,事情並沒有符合我的期望,但我不知道是因為有什麼不對勁,還是我的期望是錯誤的。

所以,我有一個超過 100GB 記憶體的系統,我將我的設置dirty_background_bytes為 9663676416(9GB)和dirty_bytes2 倍(19327352832 或 18GB)

在我看來,這應該讓我最多可以將 9GB 寫入文件,但實際上它只是位於記憶體中,不需要訪問磁碟。我dirty_expire_centisecs的預設值為3000(30 秒)。

所以當我執行時:

# dd if=/dev/zero of=/data/disk_test bs=1M count=2000

並跑:

# while sleep 5; do egrep 'Dirty|Writeback' /proc/meminfo | awk '{print $2;}' | xargs; done

(以 kb 為單位列印 Dirty bytes,以 kb 為單位的 Writeback,以及在 5s 快照時以 kb 為單位的 WritebackTmp)

我本來希望看到它將 2GB 轉儲到頁面記憶體中,在那裡停留 30 秒,然後開始將數據寫入磁碟(因為它從未超過 9GB 背景比率)

相反,我看到的是:

3716 0 0
4948 0 0
3536 0 0
1801912 18492 0
558664 31860 0
7244 0 0
8404 0 0

頁面記憶體一跳轉,它就已經在寫數據了,直到我們回到我們開始的地方。

我實際上正在研究的基本上是試圖查看我的程序瓶頸是磁碟 IO 還是其他因素,但在中間我對這種行為感到困惑。我認為只要程序仍在緩衝區中執行,磁碟寫入性能就不應該真正相關,因為它應該只是轉儲到記憶體中。

那麼,我是否誤解了這些功能的工作方式,或者發生了什麼奇怪的事情?

這可能是您的dd命令在每次迭代時取消連結並創建新的 disk_test 的副作用。

嘗試首先使用單個dd if=/dev/zero of=/data/disk_test bs=1M count=2000命令創建目標文件,然後使用命令執行循環dd if=/dev/zero of=/data/disk_test bs=1M count=2000 conv=notrunc,nocreat

說明: notrunc有所作為,因為過去添加了一些啟發式方法以防止應用程序執行替換通過重命名和替換通過截斷並在之後崩潰以破壞其數據。這種啟發式基本上強制刷新屬於打開->寫入->截斷文件的數據。

安裝手冊頁

auto_da_alloc | noauto_da_alloc

當 noauto_da_alloc 通過以下模式替換現有文件時,許多損壞的應用程序不使用 fsync()

fd = open(“foo.new”)/write(fd,..)/close(fd)/rename(“foo.new”, “foo”)

或者更糟

fd = open(“foo”, O_TRUNC)/write(fd,..)/close(fd)。

如果啟用了 auto_da_alloc,ext4 將檢測 replace-via-rename 和 replace-via-truncate 模式並強制分配任何延遲的分配塊,以便在下一次日誌送出時,在預設的 data=ordered 模式下,在送出 rename() 操作之前,新文件被強制寫入磁碟。這提供了與 ext3 大致相同級別的保證,並避免了在延遲分配塊被強製到磁碟之前系統崩潰時可能發生的“零長度”問題。

在XFS 常見問題解答中也提供戰利品

引用自:https://serverfault.com/questions/896153