
在閱讀了一些有關 Linux VFS 頁面快取和可調參數的文章後,dirty_ratio
我的印像是頁面快取將作為讀取和寫入快取層運行。
但是使用下面的簡單測試可以很好地提高位於頁面快取中但似乎不適用於寫入的檔案的讀取速度。
例如
清除快取並寫入檔案。
# swapoff -a
# echo 3 > /proc/sys/vm/drop_caches
# dd if=/dev/zero of=/home/flo/test bs=1M count=30
30+0 records in
30+0 records out
31457280 bytes (31 MB) copied, 0.182474 s, 172 MB/s
檢查文件是否確實在頁面快取中
# vmtouch /home/flo/test
Files: 1
Directories: 0
Resident Pages: 7680/7680 30M/30M 100%
Elapsed: 0.000673 seconds
從文件中讀取以確認實際上來自快取。
# dd if=/home/flo/test of=/dev/null bs=1M count=30
30+0 records in
30+0 records out
31457280 bytes (31 MB) copied, 0.00824169 s, 3.8 GB/s
刪除快取並再次讀取以證明速度差異。
# echo 3 > /proc/sys/vm/drop_caches
# dd if=/home/flo/test of=/dev/null bs=1M count=30
30+0 records in
30+0 records out
31457280 bytes (31 MB) copied, 0.132531 s, 237 MB/s
由於我沒有將 DIRECT_IO 與 dd 一起使用,因此我希望將頁面快取用作寫回類型的快取。並且基於dirty_ratio
或dirty_expire_centiseconds
......最終資料將提交到磁碟。
有人可以解釋 VFS 如何以不同的方式處理讀取和寫入過程,特別是在寫入過程中,以及為什麼沒有速度增益。
有沒有什麼方法可以讓 vfs 在寫入快取方面更加積極,因此它的行為更像是在 raid 控制器上找到的寫回快取。
謝謝
洛
答案1
man ext4 有關於 (no) 選項的介紹auto_da_alloc
:
許多損壞的應用程式不使用 fsync()...
這背後似乎有一個很長的故事(一些關於資料遺失的悲劇)。這與延遲分配檔案系統區塊。 Ext2/3 沒有這個功能,但它不僅是 ext4 的一個非常重要的功能。
如果應用程式沒有同步,使用者也沒有手動同步,核心也沒有在 30 秒後同步,那麼當涉及到某些檔案重寫時,檔案系統最好立即執行同步。否則,有了DA,停電時很容易發生不好的事。比失去最後的更改更糟糕的事情。
如果沒有conv=notruncate
dd 命令,覆蓋時就像「應用程式」一樣。它必須刪除現有文件才能建立新文件,否則如果現有文件更長,您將獲得混合文件。
您mount -o remount,noauto_da_alloc ...
可以在 ext4 上關閉此行為。現在區塊寫入可以在截斷後很長一段時間內完成。
下一個攻擊性程度將提高定期寫回的 30 秒到期時間和 5 秒檢查間隔(/proc/sys/vm/ 中的 dirty_..._centisecs 值)。使用預設的 30/5 時,一些新檔案將在半分鐘後寫入,除非您刪除速度非常快。
VFS 對未使用頁面的攻擊性越強,檔案系統對區塊裝置的攻擊性就越小。
掛載選項和寫回參數
]# findmnt --real
TARGET SOURCE FSTYPE OPTIONS
/ /dev/sda3 ext4 rw,relatime,noauto_da_alloc
|-/root/sda1 /dev/sda1 ext2 rw,relatime
`-/root/16 /dev/sda16 ext4 rw,relatime
在這樣的設定中,覆蓋會立即在 sda16 上同步,但不會在其他兩個上同步。
目前我(想我)完全關閉了定期寫回。
]# grep '' /proc/sys/vm/*centisecs
/proc/sys/vm/dirty_expire_centisecs:720000
/proc/sys/vm/dirty_writeback_centisecs:0
現在我終於收集髒頁了:
]# grep nr_dirty /proc/vmstat
nr_dirty 10077
nr_dirty_threshold 437320
nr_dirty_background_threshold 174671
我嘗試收集它們並以某種方式接近預設的 10% 背景比例 - 昨天當我進入掛起到內存睡眠狀態時,我得到了同步。這是有道理的:誰願意和 MB 的髒頁一起睡?
mm/writeback.c
細節非常複雜,評論本身就說明了這一點。一個問題是不要錯過「1000個dd立即開始髒」時的節流點。從長遠來看,「回寫」的目標似乎是 10% 左右。正如我上面的範例所示,在正常(最少)使用情況下,這 10%(總/可用 RAM)需要很長時間才能填滿。一分鐘瀏覽大約會弄髒 1000 個頁面。
理論結束後,具體證明
我在上面列出的兩個檔案系統上測試了 10 個區塊:
]# dd if=/dev/zero of=test10 bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.0076396 s, 1.4 GB/s
]# dd if=/dev/zero of=test10 bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.00514406 s, 2.0 GB/s
-> 在根分區(sda3,上面)上使用 noauto_da_alloc 覆蓋速度更快。
在預設安裝的 ext4(上面的 sda16)上它會變慢:
]# rm test10
]# dd if=/dev/zero of=test10 bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.00800839 s, 1.3 GB/s
]# dd if=/dev/zero of=test10 bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.0740824 s, 142 MB/s
……因為整個覆蓋是同步的,如圖vmstat 1 |cut...
所示:
0 0
0 0
0 0
-----io----
bi bo
0 10240
0 0
0 0
手動sync
延遲分配
它的好處是:您可以在需要時執行此操作,並且可以對單一檔案執行此操作,也可以對整個磁碟機執行此操作。
另外:卸載、關閉(和暫停)也包括在內。
壞事是:當(覆蓋)寫入和同步之間發生崩潰/電源故障時,零長度「損壞」風險。這意味著您實際上只能安全地保存您放在一個或兩個外部儲存空間中的內容。
我找不到底線。沒有簡單的解決方案,只有很長(但至少合乎邏輯)的解釋。
答案2
為了看到快速行為,我必須rm test
先做。例如,我看到dd
報告為 1GB/s,而不是 150MB/s。
參考:
auto_da_alloc
在人 ext4。- LWN.net文章《ext4 和資料遺失」。
- XFS 在這種情況下執行相同的操作,但在其他情況下 ext4 則不會執行此操作(對現有檔案進行重新命名):https://www.spinics.net/lists/xfs/msg36717.html。
雖然參考文獻只解釋了為什麼我想嘗試這個,但它實際上並沒有解釋為什麼它會導致 IO 阻塞。
在我的電腦上,阻塞似乎只發生在新的 WBT(“寫回限制”)代碼中…該代碼於 2016 年添加,後你問了你的問題。我還沒分析過為什麼它會導致這個。當 WBT 被停用時,它就會消失。
我的核心版本是4.18.16-200.fc28.x86_64
.
strace -T
顯示所有時間都花在 close() 上,這對我來說最有意義。我perf
也嘗試使用。它沒有按預期工作,但它顯示了堆疊跟踪,例如
dd 17068 [003] 475165.381526: sched:sched_switch: dd:17068 [120] T ==> kworker/3:1H:19326 [100]
ffffffffa390c172 __sched_text_start+0x352 ([kernel.kallsyms])
ffffffffa390c172 __sched_text_start+0x352 ([kernel.kallsyms])
ffffffffa390c6a8 schedule+0x28 ([kernel.kallsyms])
ffffffffa30def32 io_schedule+0x12 ([kernel.kallsyms])
ffffffffa3461ed7 wbt_wait+0x337 ([kernel.kallsyms])
ffffffffa342ee33 blk_queue_bio+0x123 ([kernel.kallsyms])
ffffffffa342d114 generic_make_request+0x1a4 ([kernel.kallsyms])
ffffffffa342d3c5 submit_bio+0x45 ([kernel.kallsyms])
ffffffffa3377d78 ext4_io_submit+0x48 ([kernel.kallsyms])
ffffffffa335da2c ext4_writepages+0x70c ([kernel.kallsyms])
ffffffffa3209311 do_writepages+0x41 ([kernel.kallsyms])
ffffffffa31f808e __filemap_fdatawrite_range+0xbe ([kernel.kallsyms])
ffffffffa334b9ec ext4_release_file+0x6c ([kernel.kallsyms])
ffffffffa32a9d4e __fput+0xae ([kernel.kallsyms])
ffffffffa30cf474 task_work_run+0x84 ([kernel.kallsyms])
ffffffffa3003e6e exit_to_usermode_loop+0xce ([kernel.kallsyms])
ffffffffa300425d do_syscall_64+0x14d ([kernel.kallsyms])
ffffffffa3a00088 entry_SYSCALL_64_after_hwframe+0x44 ([kernel.kallsyms])
7fcca3a60654 __close+0x14 (/usr/lib64/libc-2.27.so)
這提醒我目前正在測試deadline
I/O 調度程序,並啟用了 WBT(「寫回限制」)。停用 WBT(包括切換到不相容的 CFQ)讓我再次獲得快速行為!
perf
我用來看到這個的命令是:
sudo perf record -e sched:sched_stat_sleep -e sched:sched_switch -e sched:sched_process_exit -gP -o ~/perf.data dd if=/dev/zero of=test bs=1M count=30
sudo perf script -i ~/perf.data | cat
答案3
只是不要使用dd
。例如,使用cp
,您將獲得用於寫入的頁面快取。