
После прочтения некоторых статей о кэше страниц 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 есть введение о (нет) auto_da_alloc
опции:
Многие неработающие приложения не используют fsync()...
Кажется, за этим стоит длинная история (какая-то трагедия с потерей данных). Это связано сотложенное распределениеблоков файловой системы. В Ext2/3 этого не было, но это довольно важная функция не только ext4.
Если приложение не синхронизируется, и ни пользователь вручную, а ядро только через 30 секунд, то файловой системе лучше сделать это сразу, когда происходит перезапись файлов. В противном случае, с DA, плохие вещи могут легко произойти при отключении питания. Хуже, чем просто потеря последних изменений.
Без conv=notruncate
команды dd при перезаписи действует как "приложение". Она должна избавиться от существующего файла, чтобы создать новый, иначе вы получите смесь, если существующий файл длиннее.
С помощью mount -o remount,noauto_da_alloc ...
вы можете отключить это поведение на ext4. Теперь запись блока может быть сделана долгое время после усечения.
Следующийуровень агрессиибыло бы увеличить время истечения срока действия до 30 с и интервал проверки до 5 с (значения dirty_..._centisecs в /proc/sys/vm/) для периодических обратных записей. При значении по умолчанию 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% - вчера я синхронизировался, когда перешел в режим ожидания-в-оперативную память. Логично: кто хочет спать с мегабайтами грязных страниц?
mm/writeback.c
очень сложно в деталях, говорят сами комментарии. Одна проблема — не пропустить точку дросселирования, когда «1000 dd начинают загрязняться сразу». «Обратная запись», похоже, нацелена на эти 10% bg-ratio в долгосрочной перспективе. Как показывает мой пример выше, эти 10% (от общего/доступного ОЗУ) долго заполняются при нормальном (минимальном) использовании. Минута просмотра загрязняет 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
-> с noauto_da_alloc на корневом разделе (sda3, выше) перезапись происходит еще быстрее.
На смонтированном по умолчанию 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
отчет 1 ГБ/с вместо 150 МБ/с.
Использованная литература:
auto_da_alloc
вчеловек ext4.- Статья LWN.net "ext4 и потеря данных".
- В этом случае XFS делает то же самое, но в другом случае ext4 делает то же самое (переименование существующего файла):https://www.spinics.net/lists/xfs/msg36717.html.
Хотя ссылки только объясняют, почему я решил попробовать это, они на самом деле не объясняют, почему это приводит к блокировке ввода-вывода.
На моем компьютере блокировка, похоже, происходила только внутри нового кода 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
планировщик ввода-вывода с включенным WBT ("writeback throttling"). Отключение 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
, и вы получите pagecache для записей, все в порядке.