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

Как удалить миллионы файлов, не беспокоя сервер

Я хочу удалить каталог кеша nginx, который я быстро очистил:

mv cache cache.bak
mkdir cache
service nginx restart

Теперь у меня есть cache.bak папка с 2 миллионами файлов. Я хочу удалить его, не мешая серверу.

Простой rm -rf cache.bak уничтожает сервер, даже самый простой ответ HTTP занимает 16 секунд во время работы rm, поэтому я не могу этого сделать.

Я попытался ionice -c3 rm -rf cache.bak, но это не помогло. На сервере есть жесткий диск, а не SSD, возможно, на SSD это не проблема.

Я считаю, что лучшим решением было бы какое-то дросселирование, например, как это делает встроенный диспетчер кешей nginx.

Как бы вы это решили? Есть ли какой-нибудь инструмент, который может это сделать?

ext4 в Ubuntu 16.04

Сделайте такой сценарий bash:

#!/bin/bash
rm -- "$*"
sleep 0.5

Сохраните это с именем deleter.sh например. Бегать chmod u+x deleter.sh чтобы сделать его исполняемым.

Этот сценарий удаляет все файлы, переданные ему в качестве аргументов, а затем засыпает 0,5 секунды.

Затем вы можете запустить

find cache.bak -print0 | xargs -0 -n 5 deleter.sh

Эта команда получает список всех файлов в cache.bak и передает пять имен файлов одновременно сценарию удаления.

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

Вам следует подумать о сохранении кеша в отдельной файловой системе, которую вы можете монтировать / размонтировать, как кто-то сказал в комментариях. Пока вы этого не сделаете, вы можете использовать этот лайнер /usr/bin/find /path/to/files/ -type f -print0 -exec sleep 0.2 \; -exec echo \; -delete предполагая, что ваш двоичный файл find находится в / usr / bin и вы хотите видеть прогресс на экране. Отрегулируйте режим сна соответствующим образом, чтобы не перегружать жесткий диск.

Вы можете попробовать ionice на скрипте, использующем вывод команды find. Примерно так:

ionice -c3 $(
for file in find cache.bak -type f; do
    rm $file
done
for dir in find cache.bak -depthe -type d -empty; do
    rmdir $dir
done
)

В зависимости от файловой системы каждое удаление файла может привести к перезаписи всего каталога. Для больших каталогов это может быть настоящим хитом. Требуются дополнительные обновления для таблицы inode и, возможно, списка свободного места.

Если в файловой системе есть журнал, изменения записываются в журнал; применяется; и удален из журнала. Это увеличивает требования к вводу-выводу для операций с интенсивной записью.

Вы можете использовать файловую систему без журнала для кеша.

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

У меня здесь много полезных ответов / комментариев, которые я хотел бы завершить, а также показать свое решение.

  1. Да, лучший способ предотвращать такое происходит, когда каталог кеша хранится в отдельной файловой системе. Nuking / быстрое форматирование файловой системы всегда занимает максимум несколько секунд (возможно, минут), независимо от того, сколько файлов / каталогов было на ней.

  2. В ionice / nice решения ничего не сделали, потому что процесс удаления фактически почти не вызвал операций ввода-вывода. Причиной ввода-вывода я считаю, что очереди / буферы уровня ядра / файловой системы заполняются, когда файлы удалялись слишком быстро в процессе удаления.

  3. То, как я решил это, похоже на решение Теро Килканена, но не требовало вызова сценария оболочки. Я использовал встроенный rsync --bwlimit переключатель, чтобы ограничить скорость удаления.

Полная команда была:

mkdir empty_dir
rsync -v -a --delete --bwlimit=1 empty_dir/ cache.bak/

Теперь bwlimit указывает пропускную способность в килобайтах, которая в данном случае применяется к имени файла или пути к файлам. Установив его на 1 Кбит / с, он удалял около 100 000 файлов в час или 27 файлов в секунду. У файлов были относительные пути, например cache.bak/e/c1/db98339573acc5c76bdac4a601f9ec1e, длина которого составляет 47 символов, так что это даст 1000/47 ~ = 21 файл в секунду, что похоже на мое предположение о 100 000 файлов в час.

Теперь почему --bwlimit=1? Я пробовал разные значения:

  • 10000, 1000, 100 -> система замедляется как раньше
  • 10 -> система некоторое время работает неплохо, но производит частичное замедление примерно раз в минуту. Время ответа HTTP все еще <1 сек.
  • 1 -> никакого замедления системы. Я никуда не тороплюсь, таким способом можно удалить 2 миллиона файлов за <1 день, поэтому я выбираю его.

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