Назад | Перейти на главную страницу

Удаление большого количества файлов в linux съедает процессор

Я генерирую более 50 ГБ файлов кеша на моем сервере RHEL (а типичный размер файла составляет 200 КБ, поэтому файлы огромны). Когда я пытаюсь удалить эти файлы, это занимает 8-10 часов.

Однако более серьезная проблема заключается в том, что в течение этих 8-10 часов загрузка системы становится критической. Есть ли способ держать нагрузку системы под контролем во время удаления?

Я пробовал использовать

nice -n19 rm -rf *

но это не помогает в загрузке системы.

P.S. Я задал тот же вопрос о superuser.com но не получил достаточно хорошего ответа, поэтому пытаюсь здесь.

Вот некоторые ориентиры для различных операций и файловых систем для справки. (Конечно, в загруженной системе у вас будут другие результаты, но, надеюсь, это даст вам представление о том, чего ожидать).

Если бы я был в вашем кресле, я бы попытался получить базовую оценку сценария:

  • установить, сколько времени займет операция на голом оборудовании, изолированном от всего остального (и да, это должно занять гораздо, гораздо меньше 7-8 часов даже на довольно старом оборудовании).
  • попробуйте добавить другие операции, которые обычно выполняются контролируемым образом, и посмотрите, что на самом деле заставляет его работать так долго

Некоторые цифры.

На тетради 5-летней давности ext3 смонтированный rw, noatime, running top и больше ничего, создайте 10k каталогов с помощью сценария оболочки create10kdirs.sh

#!/bin/bash
for i in $(seq 10000)
do
    mkdir $i
done

sudo time ./create10kdirs.sh
24.59 пользователь
20.70система
0: 47.04 прошло
96% ЦП (0avgtext + 0avgdata 0maxresident) k80inputs + 8outputs (1major + 2735150minor) pagefaults 0swaps

удалить 10k каталогов с помощью sudo time rm -rf
0.10 пользователь
19,75система
0: 20.71 прошло
95% ЦП (0avgtext + 0avgdata 0maxresident) k0inputs + 8outputs (0major + 222minor) pagefaults 0swaps

такое же оборудование, ext4 смонтированный rw, noatime создать 10k каталогов с помощью сценария оболочки sudo time create10kdirs.sh
23.96 пользователь
22.31система
0: 49.26 прошло
93% CPU (0avgtext + 0avgdata0maxresident) k1896inputs + 8outputs (20major + 2715174minor) pagefaults 0swaps

удалить 10k каталогов с помощью sudo time rm -rf
0,13 пользователь
16.96система
0: 28.21 прошло
60% ЦП (0avgtext + 0avgdata0maxresident) k10160inputs + 0outputs (1major + 219minor) pagefaults0swaps

Тетрадь 4-х летней давности, xfs установленный rw, relatime, nobarrier на USB sudo time create10kdirs.sh
14.19 пользователь
13.86система
0: 29.75 прошло
94% ЦП (0avgtext + 0avgdata0maxresident) k432inputs + 0outputs (1major + 2735243minor) pagefaults 0swaps

удалить 10k каталогов с помощью
sudo time rm -rf
0,13 пользователь
2.65система
0: 08.20 прошло
33% ЦП (0avgtext + 0avgdata 0maxresident) k120inputs + 0outputs (1major + 222minor) pagefaults 0swaps

Вывод: это старое оборудование стирает 400 тыс. Маленьких файлов + папок на ext3 примерно за 21 с * 40 = 12 мин 40 с. На xfs (без барьеров) это будет примерно за 5 мин. 20 сек. Конечно, в обоих случаях тестовая машина не находилась под большой нагрузкой, но мне кажется, что ваши проблемы не связаны строго с вашим выбором файловой системы.

EDIT2 Кроме того, после выполнения вышеуказанных тестов я пошел попробовать удалить с помощью find. -mindepth 1 -maxdepth 1 -delete

и результаты !:

ext3 удаляет 10k каталогов с помощью sudo time find. -mindepth 1 -maxdepth 1 -delete
0,04 пользователя
0.44система
0: 00.88прошло
55% ЦП (0avgtext + 0avgdata 0maxresident) k516inputs + 8outputs (1major + 688minor) pagefaults0swaps

ext4 удалить 10k каталогов с помощью
sudo time find. -mindepth 1 -maxdepth 1 -delete
0,05 пользователя
0.66система
0: 01.02 прошло
70% ЦП (0avgtext + 0avgdata 0maxresident) k568inputs + 0outputs (1major + 689minor) подкачки страниц

xfs удаляет 10k каталогов с помощью
sudo time find. -mindepth 1 -maxdepth 1 -delete
0,06 пользователя
0.84система
0: 04.55 прошло
19% ЦП (0avgtext + 0avgdata 0maxresident) k416inputs + 0outputs (3major + 685minor) pagefaults 0swaps

Реальный вывод заключается в том, что rm -rf не очень умен и неэффективен для больших деревьев. (при условии, что мой тестовый пример действительно репрезентативен).

Примечание: я также тестировал вариант xargs, он быстрый, но не такой быстрый, как указано выше.

Как вы упомянули в комментарии, вы используете ext3.

Хорошо известно, что rm производительность для больших файлов на ext3 оставляет желать лучшего; это одна из вещей, которые были зафиксированы в ext4. См. Например эта почта, или ядро новички (где упоминается, что экстенты улучшают скорость удаления и усечения для больших файлов).

Я не знаю, насколько это применимо к вашим типичным размерам файлов. Я бы ожидал, что это применится хотя бы немного, так как примерно с 200 КБ вы уже будете использовать косвенные блоки на ext3, по сравнению, возможно, с одним экстентом на ext4.


В качестве обходного пути (поскольку вы, вероятно, не перейдете на ext4 только для этого), каждый раз удаляйте только несколько файлов и добавляйте sleep между удалениями. Это некрасиво, но должно помочь снизить нагрузку.

Кроме того, если потеря файлов при отключении питания не является проблемой (поскольку это какой-то кеш), вы можете поместить их в отдельный раздел, который вы mkfs снова при загрузке и используйте ext3 без журнала или даже ext2. Причиной высокой нагрузки, вероятно, является сбрасывание журнала на диск, конфликтующий с чтениями (вы упомянули в другом сообщении, что у вас много одновременных чтений).

Возможно оболочка является причиной проблемы. Вы должны использовать прямой поиск: find /dir -mindepth 1 -maxdepth 1 -delete

Это может быть связано, а может и не быть, но у меня были случаи, когда rm не мог обработать количество файлов, которые я предоставил ему в командной строке (через оператор звездочки). Вместо этого я бы использовал следующую команду из оболочки:

for i in *; do rm -rf $i; done

В этом случае вы можете удалять деревья, и в этом случае вышеуказанное может не дать того, что вам нужно. Возможно, вам придется разделить операцию удаления на части, например

for i in [a-mA-M]*; do rm -rf $i; done
for i in [n-zN-Z]*; do rm -rf $i; done

Это всего лишь 250 000 файлов или около того, на самом деле не должно быть проблемой - какую файловую систему вы используете и используется ли этот том для чего-нибудь еще?

Когда у вас много файлов, как вы описали, вы каждый раз вызываете команду. Также вы должны иметь в виду, что в журналируемой FS вы имеете дело с попаданиями в буфер и метаданными, которые могут сильно повлиять на время процесса.

Лучше всего использовать команду find, как упомянуто выше, только с менее очевидной функцией.

find / -name filename.* -exec /bin/rm -f '{}' \+

В основном "+" - ваш друг. Это создает имена файлов в наборах и вызывает команду rm один раз для каждого набора. Это почти то же самое, что и xargs, но вам не нужно беспокоиться о правильных флагах, если вы используете BSD / Linux.

Очень любопытно, насколько это ускоряет для вас. Так что ответьте, если вы все еще здесь. Удачи !

Изучив тесты файловой системы, я выбрал JFS в качестве хранилища файлов для моих видеофайлов Mythtv, потому что файлы удаляются быстро (а мифы ожидают завершения удаления, что замедляет ввод-вывод).

Вы также можете вызвать rm через find и xargs вместо rm -rf. Это могло быть быстрее:

find <dir> | xargs rm

Как насчет того, чтобы передать список этих файлов Perl и использовать его функцию unlink?

find <dir> | perl -nle 'unlink;'

Я согласен, что это не займет так много времени, но в зависимости от используемого базового хранилища этого можно ожидать при интенсивном чтении. Я думаю, что в конечном итоге ваше лучшее решение - добавить дополнительные диски и разделить вашу деятельность между ними. RAID может помочь в некоторых сценариях, если вы пойдете по этому пути. Что говорит вам iostat в это время? Вы также можете использовать цикл for и заключить команды 'rm' во 'time', чтобы получить дополнительную информацию.

Другая возможность, конечно, в зависимости от вашей настройки и приложения, но, может быть, вы могли бы сделать эти файлы кеша в другом разделе и просто периодически форматировать диск, а не удалять файлы? Я думаю, что запуск mkfs значительно сократит время, но ваше приложение будет недоступно, пока это произойдет, поэтому оно не будет идеальным.

Мне также нравится идея почаще их убирать. Скажем, в cron вы планируете что-то вроде этого каждый час:

find ./ -maxdepth 1 -type f -name "some pattern" -ctime +1 -exec rm -f {} \;

Это приведет к удалению всех файлов старше 24 часов, вместо того, чтобы пытаться сделать их все сразу.