запутался в скорости записи dd и кэше страниц VFS

запутался в скорости записи dd и кэше страниц VFS

После прочтения некоторых статей о кэше страниц 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 МБ/с.

Использованная литература:

Хотя ссылки только объясняют, почему я решил попробовать это, они на самом деле не объясняют, почему это приводит к блокировке ввода-вывода.

На моем компьютере блокировка, похоже, происходила только внутри нового кода 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 для записей, все в порядке.

Связанный контент