- Удалить миллионы файлов в linux
- Удаление миллионов файлов
- 5 ответов 5
- Как удалить большое количество файлов в Linux
- Необычное переполнение жесткого диска или как удалить миллионы файлов из одной папки
- Предисловие
- Начало
- Проблема
- Решение
- Так как же удалить миллионы файлов из одной папки?
- Подготовка
- Тесты
- Удаление через rm -r
- Удаление через rm ./*
- Удаление через find -exec
- Удаление через find -delete
- Удаление через ls -f и xargs
- Удаление через perl readdir
- Удаление через программу на C readdir + unlink
Удалить миллионы файлов в linux
Как удалить миллионы файлов в linux? Проблемам достаточно известная и, самое главное, не так проста как кажется. Симптомы:
- Невозможно сделать ls в папке, зависает терминал
- Невозможно удалить так же в MC по той же причине невозможно зайти в папку.
- Консольные утилиты отказываются удалять файлы поскольку Argument list too long
- find ls так же выдают Как удалить миллионы файлов в linux Argument list too long
При наличии в одном каталоге нужных нам файлов и ненужных, мы вынуждены удалять файлы по маске, и тут кроется основная проблема большинство консольных утилит не в состояние выдать вам столь весомый список, а следствие этого и работать с ним. Первым отваливается rm который вам заявляет что слишком большой массив данных.
При определенном условие все еще отрабатывает такой хитрый вариант как
Оптимизировав его мы можем добавить еще пару сотен тысяч файлов и опять же у нас появится та же проблема, слишком большой массив данных.
Основная проблема в том, что мне нужно удалить именно данный файл, а не всю папку или все файлы находящиеся в ней. В результате для удаления 14 000 000 файлов мне потребовалось сделать ход конем в первую очередь отказаться от регулярок, поскольку они требуют построения всего дерева. И отказаться от любых утилит, составляющих весь список в пользу построчного построения. Используем тот же find
Далее, после получения файла, в моем случае он было около 200 мегабайт, подставляем ко всем
Естественно, вариант смотрится достаточно страшно, и не оптимально. Но он помог мне решить задачу которая не поддалась никаким другим вариантам.
Самое главное в find не должно быть никаких регулярок! В противном случае он так же откажется работать, все что нам потребуется отсортируем уже в файле. Ну и напоследок не доводите до такого, в моем случае не удалялись сессии. Естественно, после формирования файла с командами нам потребуется их исполнить
Источник
Удаление миллионов файлов
У меня был каталог, заполненный миллионами изображений в формате gif. Слишком много для команды rm.
Я пытался найти команду поиска следующим образом:
Проблема в том, что это сильно тормозит мою машину и приводит к тайм-ауту клиентов, так как это сервер.
Есть ли способ, чтобы быстрее удалить все эти файлы . без блокировки машины?
5 ответов 5
Быстрее не обязательно то, что вы хотите. Возможно, вы захотите работать медленнее, поэтому удаление во время работы отнимает меньше ресурсов.
Используйте nice(1), чтобы понизить приоритет команды.
Для процессов, связанных с вводом / выводом, nice(1) может быть недостаточно. Планировщик Linux принимает во внимание ввод / вывод, а не только процессор, но вам может потребоваться более точное управление приоритетом ввода / вывода.
Если этого не произойдет, вы также можете добавить сон, чтобы действительно замедлить его.
Поскольку вы работаете в Linux, и эта задача, вероятно, связана с вводом / выводом, я советую дать вашей команде приоритет планировщика ввода / вывода с использованием ionice(1) :
По сравнению с вашей исходной командой, я полагаю, что это может сэкономить еще несколько циклов ЦП, избегая перехода на xargs .
Нет более быстрого способа, приложения из soft-формата диска. Файлы передаются rm сразу (до предела командной строки, его также можно установить в xargs ), что намного лучше, чем вызывать rm для каждого файла. Так что нет, определенно нет более быстрого пути.
Использование nice (или renice в запущенном процессе) помогает только частично, потому что это для планирования ресурсов процессора , а не диска! И использование процессора будет очень низким. Это слабое место в Linux — если один процесс «съедает» диск (т.е. много с ним работает), вся машина зависает. Модифицированное ядро для использования в реальном времени может быть решением.
На сервере я бы позволил другим процессам выполнять свою работу вручную, включая паузы, чтобы сервер «дышал»:
Это будет ждать 5 секунд после каждых 100 файлов. Это займет гораздо больше времени, но ваши клиенты не должны замечать каких-либо задержек.
Если количество файлов, которые должны быть удалены, значительно превосходит количество оставленных файлов, возможно, не самый эффективный подход — пройтись по дереву файлов, которые нужно удалить, и выполнить все эти обновления файловой системы. (Это аналогично выполнению неуклюжего управления памятью с подсчетом ссылок, посещению каждого объекта в большом дереве, чтобы отбросить ссылку, вместо того, чтобы за один шаг превратить все ненужное в мусор, а затем просмотр всего, что доступно для очистки.)
То есть клонировать части дерева, которые должны быть сохранены, в другой том. Пересоздайте новую чистую файловую систему на исходном томе. Скопируйте сохраненные файлы обратно в их исходные пути. Это примерно похоже на копирование сборки мусора.
Будет некоторое время простоя, но это может быть лучше, чем постоянная плохая производительность и нарушение работы.
Это может быть непрактично в вашей системе и ситуации, но легко представить очевидные случаи, когда это путь.
Например, предположим, что вы хотите удалить все файлы в файловой системе. Какой смысл повторять и удалять по одному? Просто размонтируйте его и выполните «mkfs» поверх раздела, чтобы создать пустую файловую систему.
Или предположим, что вы хотите удалить все файлы, кроме полдюжины важных? Получите полдюжины оттуда и . «mkfs» поверх.
В конечном итоге наступает момент безубыточности, когда достаточно файлов, которые должны остаться, и рекурсивное удаление становится дешевле, принимая во внимание другие затраты, такие как простои.
Источник
Как удалить большое количество файлов в Linux
Удалять файлы можно используя утилиту find, в отличие от ls или rm с указанием маски она не формирует изначально список содержимого каталога, а перебирает файлы по одному.
Посчитать количество файлов можно так
find /home/web/example.com/www/opt/cache/ -type f ¦ wc -l
С -exec rm -f можно запустить процесс удаления файлов (он может занять длительное время)
find /home/web/example.com/www/opt/cache/ -type f -exec rm -f <> \;
Можно попробовать find с опцией delete
find /home/web/example.com/www/opt/cache/ -type f -delete
Скорее всего не даст никакого результата rm с указанием файлов по маске — система при этом до того как начать удаление попытается сформировать полный список файлов, что сделать не получится
Также существует вариант с ls -f, вывод которого перенаправляется в xargs по 100 файлов, затем удаляемых при помощи rm. Может успешно отрабатывать, однако если файлов слишком много вывести список не получится и с ls -f
cd /home/web/example.com/www/opt/cache/ ; ls -f . | xargs -n 100 rm
Самой эффективной командой обычно оказывается find с -exec rm -f, однако все зависит от количества файлов и использовать стоит все представленные варианты (приоритет процессов при удалении имеет смысл максимально понижать используя nice и ionice — алиасы для find или других команд можно добавить в .bashrc пользователя, от имени которого производится удаление).
Источник
Необычное переполнение жесткого диска или как удалить миллионы файлов из одной папки
Предисловие
Начало
Ничто не предвещало беды.
Сервер с сайтом работал без никаких проблем уже больше года (uptime почти 500 дней), не было никаких проблем, и я с чистой душой спокойно ушел в отпуск.
В первый же день отпуска мне звонят с жалобой — сайт недоступен. MySQL падает с ошибкой Error 28 «No space left on device».
Казалось бы, проблема банальна — кончилось место на диске. Правда, df -h показывает, что на диске имеется вполне достаточное количество свободного места, ну да я же в отпуске, разбираться лень — посоветовал им поискать на диске ненужные файлы (старые бекапы и т.д.) и их удалить. Удалили, вроде все заработало.
Прошла пара часов и проблема вернулась. Странно — свободное место на жестком диске за это время практически не уменьшилось. После беглого гугления обнаружился топик на serverfault, в котором говорится, что проблема может возникнуть также из-за того, что кончилось не место на диске, а айноды!
Ввожу в консоль df -i — и оказывается действительно, айноды у меня закончились.
Проблема
Начал искать, где же у меня находится столько файлов на жестком диске, что они сожрали все айноды (а айнодов у меня на 500-гигабайтном жестком диске больше 30 миллионов).
И нашел — оказалось, проблема была в папке с сессиями php.
Видимо, по какой-то причине сломался механизм автоочистки этой папки, что привело к тому, что в ней скопилось огромное количество файлов. Насколько огромное — сказать сложно, потому что никакие стандартные команды линукс, такие, как ls, find, rm и т.д. — с этой папкой не работают. Просто виснут, заодно подвешивая весь сервер. Могу только сказать, что сам файл директории стал весит около гигабайта, а также что файлов там точно более полумиллиона, потому что столько я оттуда уже удалил.
Решение
Решение очевидное — надо удалить все эти файлы сессий. При этом желательно, чтобы сервер продолжал работать в штатном режиме. Для начала я переименовал папку сессий, в которой лежит куча файлов, а вместо нее создал пустую — чтобы спокойно из старой (переименованной) удалять все файлы, и чтобы это не мешало созданию новых файлов сессий.
Также в крон добавил автоматическое удаление файлов сессий старше одного часа, чтобы проблема больше не повторилась.
И перешел к основной проблеме — очистке жесткого диска.
Попробовал решение «в лоб»:
Сервер повис, ничего не удалилось
Попробовал известный способ для удаления большого числа файлов
Ничего, сервер виснет, файлы не удаляются.
А теперь что самое интересное — файловый менеджер mc достаточно успешно справлялся с задачей удаления этих файлов! То есть, когда запускаешь удаление папки — файлы удаляются, mc не виснет. Удаление идет со скоростью примерно 5 000 файлов в минуту, правда при этом создается огромная нагрузка на жесткий диск, что приводит к неработоспособности сервера.
А хотелось бы, чтобы эти файлы постепенно удалялись в фоновом режиме, и не мешали нормальной работе сайта.
Собственно, решение опять нашлось в гугле — Olark делится способом, как он отобразил список из 8 миллионов файлов в 1 папке, используя системный вызов getdents
Здесь находится документация по функции getdents, а также пример кода, который ее использует.
Правда, этот пример мне не совсем подошел — даже если ставить большой размер буфера, как советует Olark в своем блоге, все равно сервер виснет при попытке прочитать всю папку разом.
Опытным путем подобрал размер буфера в 30 килобайт, который позволяет считать около 550 названий файлов из директории, при этом не подвешивая сервер и не создавая излишней нагрузки на диск. А также немного переписал код примера, чтобы вместо отображения имени файла он его удалял.
В итоге у меня получился такой код:
Код компиллируется обычным gcc
И просто запускается из командной строки:
Получившийся файл я поставил в крон и теперь у меня удаляется по 547 файлов в минуту, при этом нагрузка на сервер в пределах нормы — и я надеюсь, в течение недели-другой все файлы все-таки удалятся.
Источник
Так как же удалить миллионы файлов из одной папки?
Феерическая расстановка точек над i в вопросе удаления файлов из переполненной директории.
Прочитал статью Необычное переполнение жесткого диска или как удалить миллионы файлов из одной папки и очень удивился. Неужели в стандартном инструментарии Linux нет простых средств для работы с переполненными директориями и необходимо прибегать к столь низкоуровневым способам, как вызов getdents() напрямую.
Для тех, кто не в курсе проблемы, краткое описание: если вы случайно создали в одной директории огромное количество файлов без иерархии — т.е. от 5 млн файлов, лежащих в одной единственной плоской директории, то быстро удалить их не получится. Кроме того, не все утилиты в linux могут это сделать в принципе — либо будут сильно нагружать процессор/HDD, либо займут очень много памяти.
Так что я выделил время, организовал тестовый полигон и попробовал различные средства, как предложенные в комментариях, так и найденные в различных статьях и свои собственные.
Подготовка
Так как создавать переполненную директорию на своём HDD рабочего компьютера, потом мучиться с её удалением ну никак не хочется, создадим виртуальную ФС в отдельном файле и примонтируем её через loop-устройство. К счастью, в Linux с этим всё просто.
Создаём пустой файл размером 200Гб
Многие советуют использовать для этого утилиту dd, например dd if=/dev/zero of=disk-image bs=1M count=1M , но это работает несравнимо медленнее, а результат, как я понимаю, одинаковый.
Форматируем файл в ext4 и монтируем его как файловую систему
К сожалению, я узнал об опции -N команды mkfs.ext4 уже после экспериментов. Она позволяет увеличить лимит на количество inode на FS, не увеличивая размер файла образа. Но, с другой стороны, стандартные настройки — ближе к реальным условиям.
Создаем множество пустых файлов (будет работать несколько часов)
Кстати, если в начале файлы создавались достаточно быстро, то последующие добавлялись всё медленнее и медленнее, появлялись рандомные паузы, росло использование памяти ядром. Так что хранение большого числа файлов в плоской директории само по себе плохая идея.
Проверяем, что все айноды на ФС исчерпаны.
Размер файла директории
Теперь попробуем удалить эту директорию со всем её содержимым различными способами.
Тесты
После каждого теста сбрасываем кеш файловой системы
sudo sh -c ‘sync && echo 1 > /proc/sys/vm/drop_caches’
для того чтобы не занять быстро всю память и сравнивать скорость удаления в одинаковых условиях.
Удаление через rm -r
$ rm -r /mnt/test_dir/
Под strace несколько раз подряд (. ) вызывает getdents() , затем очень много вызывает unlinkat() и так в цикле. Занял 30Мб RAM, не растет.
Удаляет содержимое успешно.
Т.е. удалять переполненные директории с помощью rm -r /путь/до/директории вполне нормально.
Удаление через rm ./*
$ rm /mnt/test_dir/*
Запускает дочерний процесс шелла, который дорос до 600Мб, прибил по ^C . Ничего не удалил.
Очевидно, что glob по звёздочке обрабатывается самим шеллом, накапливается в памяти и передается команде rm после того как считается директория целиком.
Удаление через find -exec
$ find /mnt/test_dir/ -type f -exec rm -v <> \;
Под strace вызывает только getdents() . процесс find вырос до 600Мб, прибил по ^C . Ничего не удалил.
find действует так же, как и * в шелле — сперва строит полный список в памяти.
Удаление через find -delete
$ find /mnt/test_dir/ -type f -delete
Вырос до 600Мб, прибил по ^C . Ничего не удалил.
Аналогично предыдущей команде. И это крайне удивительно! На эту команду я возлагал надежду изначально.
Удаление через ls -f и xargs
$ cd /mnt/test_dir/ ; ls -f . | xargs -n 100 rm
параметр -f говорит, что не нужно сортировать список файлов.
Создает такую иерархию процессов:
ls -f в данной ситуации ведет себя адекватнее, чем find и не накапливает список файлов в памяти без необходимости. ls без параметров (как и find ) — считывает список файлов в память целиком. Очевидно, для сортировки. Но этот способ плох тем, что постоянно вызывает rm , чем создается дополнительный оверхед.
Из этого вытекает ещё один способ — можно вывод ls -f перенаправить в файл и затем удалить содержимое директории по этому списку.
Удаление через perl readdir
$ perl -e ‘chdir «/mnt/test_dir/» or die; opendir D, «.»; while ($n = readdir D) < unlink $n >‘ (взял здесь)
Под strace один раз вызывает getdents() , потом много раз unlink() и так в цикле. Занял 380Кб памяти, не растет.
Удаляет успешно.
Получается, что использование readdir вполне возможно?
Удаление через программу на C readdir + unlink
$ gcc -o cleandir cleandir.c
$ ./cleandir
Под strace один раз вызывает getdents() , потом много раз unlink() и так в цикле. Занял 128Кб памяти, не растет.
Удаляет успешно.
Опять — же, убеждаемся, что использовать readdir — вполне нормально, если не накапливать результаты в памяти, а удалять файлы сразу.
Источник