Linux

生成大量臟頁會阻塞同步寫入

  • December 16, 2015

我們有程序在後台寫入大文件。我們希望這些對其他流程的影響最小。

這是在 SLES11 SP4 上實現的測試。伺服器擁有大量記憶體,可以創建 4GB 的髒頁。

> dd if=/dev/zero of=todel bs=1048576 count=4096
4096+0 records in
4096+0 records out
4294967296 bytes (4.3 GB) copied, 3.72657 s, 1.2 GB/s
> dd if=/dev/zero of=zer oflag=sync bs=512 count=1  
1+0 records in
1+0 records out
512 bytes (512 B) copied, 16.6997 s, 0.0 kB/s

real    0m16.701s
user    0m0.000s
sys     0m0.000s
> grep Dirty /proc/meminfo
Dirty:           4199704 kB

這是我到目前為止的調查:

  • SLES11 SP4 (3.0.101-63)
  • 類型 ext3 (rw,nosuid,nodev,noatime)
  • 截止日期調度程序
  • 當時超過 120GB 的可回收記憶體
  • dirty_ratio 設置為 40%,dirty_background_ratio 10%,30s 過期,5s writeback

以下是我的問題:

  • 在測試結束時有 4GB 臟記憶體,我得出結論,在上述測試中沒有呼叫 IO 調度程序。是對的嗎?
  • 由於第一個 dd 完成後緩慢仍然存在,我得出結論,這個問題也與核心分配記憶體或 dd 填充他的緩衝區時發生的任何“寫入時複製”無關(dd 總是從同一個 buf 寫入)。
  • 有沒有辦法更深入地調查被阻止的內容?有什麼有趣的櫃檯值得關注嗎?對爭論的來源有任何想法嗎?
  • 我們正在考慮減少dirty_ratio值,或者在同步模式下執行第一個dd。還有什麼其他的調查方向嗎?將第一個 dd 同步放置有缺點嗎?恐怕它會優先於其他執行非同步寫入的“合法”程序。

也可以看看

https://www.novell.com/support/kb/doc.php?id=7010287

限制linux後台刷新(臟頁)

https://stackoverflow.com/questions/3755765/what-posix-fadvise-args-for-sequential-file-write/3756466?sgp=2#3756466

http://yarchive.net/comp/linux/dirty_limits.html


編輯:

同一設備下有一個**ext2文件系統。**在這個設備上,根本沒有凍結!唯一的性能影響發生在刷新臟頁期間,同步呼叫可能需要 0.3 秒,這與我們使用 ext3 文件系統的體驗相差甚遠。


編輯2:

在@Matthew Ife 評論之後,我嘗試在沒有 O_TRUNC 的情況下進行同步寫入打開文件,你不會相信結果!

> dd if=/dev/zero of=zer oflag=sync bs=512 count=1
> dd if=/dev/zero of=todel bs=1048576 count=4096
> dd if=/dev/zero of=zer oflag=sync bs=512 count=1 conv=notrunc
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.000185427 s, 2.8 MB/s

dd 正在使用參數打開文件:

open("zer", O_WRONLY|O_CREAT|O_TRUNC|O_SYNC, 0666) = 3

使用 notrunc 選項進行更改,現在是

open("zer", O_WRONLY|O_CREAT|O_SYNC, 0666) = 3

同步寫入立即完成!

好吧,這對我的案例來說並不完全令人滿意(我正在以這種方式進行 msync 。但是我現在能夠跟踪 write 和 msync 的不同之處!


最後編輯:我不敢相信我打了這個: https ://www.novell.com/support/kb/doc.php?id=7016100

實際上在 SLES11 下 dd 是用

open("zer", O_WRONLY|O_CREAT|O_DSYNC, 0666) = 3

和 O_DSYNC == O_SYNC!

結論:

對於我的案例,我可能應該使用

dd if=/dev/zero of=zer oflag=dsync bs=512 count=1 conv=notrunc

在 SLES11 下,無論 strace 說什麼,執行 oflag=sync 都會真正執行 oflag=dsync。

有幾件事我很想知道結果。

  1. 最初創建大文件,fallocate然後寫入它。
  2. 將dirty_background_bytes 設置得低得多(比如1GiB)並使用CFQ 作為調度程序。請注意,在此測試中,在大執行中間執行小執行可能是更好的表示。

因此,對於選項 1,您可能會發現您避免了所有data=ordered語義,因為塊分配已經(並且很快)完成,因為它是通過預先分配的,fallocate並且元數據是在寫入之前設置的。測試是否真的是這樣是很有用的。我有一些信心,雖然它會提高性能。

對於選項 2,您可以多使用 ionice。Deadline 明顯比 CFQ 快,儘管 CFQ 嘗試組織每個程序的 IO,以便您發現它可以讓您在每個程序中更好地共享 IO。

我在某處讀到(現在找不到來源),dirty_background_ratio 將阻止針對單個送出程序的寫入(有效地使大程序變慢),以防止一個程序餓死所有其他程序。鑑於我現在能找到的關於這種行為的資訊很少,我不太相信這會奏效。

哦:我應該指出這fallocate依賴於範圍,你需要使用 ext4。

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