Наверняка все сталкивались с ситуацией, когда есть каталог с несколькими миллиардами файлов, место/inodes кончилось, всё не работает, в каталоге нет ничего важного (по крайней мере настолько важного, чтобы нельзя было удалить это ради того, чтобы сервер начал работать).. Жмем rm — arguments list too long. Или segfault. Или rm падает по памяти. А ещё веселее, если сам каталог удалять нельзя. А ещё веселее, что нужно сейчас быстро-срочно подчистить хоть сколько-нибудь.
Гугл вам будет советовать find с xargs rm или -delete, perl и ещё какую-нибудь неведомую фигню. Не верьте ему. Решение этой задачи — rsync.
— rsync в данном примере сразу начинает удалять файлы (то есть через несколько секунд вы получите хоть сколько-то inodes пустых, а через пару минут — уже приличное их количество, достаточное для нормальной работы), а не строить список файлов, как некоторые
— rsync просто идет по файлам и удаляет их нафиг без всяких размышлений. Что быстро.
А суть простая — нужно rsync-ом положить пустой каталог в тот, который нужно почистить, с опцией —delete. Тогда rsync будет просто удалять каждый файл. А если в каталоге ветвистая структура и вы знаете про parallels из прошлой статьи…
Создаём пустой каталог:
Если всё плохо и на дисках создать каталог уже нельзя, то нас всегда спасёт /dev/shm:
Вешаем на каталог те же права, которые сейчас висят на том каталоге, который мы собираемся чистить (иначе каталог станет принадлежать руту и туда никто потом не сможет писать), например:
Начинаем всё удалять:
(не протеряйте слеши в концах каталогов).
Идём пить чай, потом рестартим всё, что попадало. К завтрашнему утру rsync сможет удалить несколько десятков миллиардов файлов. А на ssd — сотен миллиардов.
Спасибо большое за ценную инфу! Взял на вооружение!
Да не за что.
Забавно:)
На продакшин серверах вы поставите раком свой сервер таким методом. IO будет с настолько большим overhead’ом, что лучше вручную удалить хотя бы пару десятков файлов. Рекомендую ознакомиться с http://blog.endpoint.com/2010/07/efficiency-of-find-exec-vs-find-xargs.html .
Так что всё-таки идеальный вариант = find+xargs.
Ну херню не неси.
IO оно поставит раком только в том случае, если с IO всё и так плохо (например, в сервере стоят sata-2 диски убитые).
Удаление файлов последовательное, никакого параллелизма там нет, занята одна IO-очередь. Соответственно, всё это прекрасно управляется через ionice (да и просто не мешает другим процессам, если сервер хорошо себя чувствует, а не убит в потолок по IO без всяких удалений файлов).
А вот с find может быть проблема, когда файлов миллиарды — он строит в памяти список, если памяти не хватает, то его прибивает OOM. Так что на виртуалке с 512 памяти find-ом удалить миллиард файлов вовсе не получится. Собственно, у меня была виртуалка с 4гб памяти и жалкие 200 млн. файлов в mod_tmp/ — тогда мне и пришлось придумывать нечто работающее.
Есть второй работающий способ с перлом (просто брать и удалять файлы, а не думать), но его запомнить намного сложнее. А вот вариант с rsync — золотая середина. И удаляет эффективно, и запомнить легко.
Позвольте полюбопытствовать, как вы поставите rsync, если inodes кончились?
С совершенно обычного сервера:
root@2:~# which rsync
root@2:~# which find
/usr/bin/find
root@2:~# which rm
/bin/rm
А еще можно примерно так:
ls -1 | while read F; do rm -f «$F» ; done
Наверняка можно еще пару способов найти которые и память не едят и юзеют только ширпотребные команды.
> А еще можно примерно так:
ls на 200 миллионах файлов тоже падает по памяти.
> можно еще пару способов найти которые и память не едят и юзеют только ширпотребные команды.
Можно найти миллиард способов. Этот удаляет файлы быстрее всего (ну кроме перлового однострочника, который из широких штанин не достанешь в панике)
Тем не менее, название статьи — «Самый быстрый и надежный способ удалить все файлы в каталоге», а не «самый распространенный», «самый простой» или какое-то подобное.
Бинарь rsync можно тоже в /dev/shm положить
> ls на 200 миллионах файлов тоже падает по памяти.
Даже если отключить всякие ненужные сортировки?
Попробовать негде — 200 млн. файлов нигде не завалялись. Максимум 11 млн. есть. И это (ls -1f) занимает меньше минуты на md raid5 из 4х sata-2 дисков. И памяти не сказать чтоб много заюзалось.
Но раз вы утверждаете, что это «Самый быстрый и надежный способ удалить все файлы в каталоге», то наверняка уже так пробовали. Насколько rsync быстрее получается?
Но мне вот интересно почему rsync не падает по памяти. Он же сравнивает каталоги прежде чем синхронизировать…
> Даже если отключить всякие ненужные сортировки?
На 130 файлах:
0.00user 0.00system 0:00.00elapsed 0%CPU (0avgtext+0avgdata 1112maxresident)k
0inputs+0outputs (0major+338minor)pagefaults 0swaps
На 200к файлов:
0.65user 0.19system 0:02.96elapsed 28%CPU (0avgtext+0avgdata 52660maxresident)k
118008inputs+0outputs (0major+13218minor)pagefaults 0swaps
50 мегабайт памяти с гаком во втором случае (оба запуска на ssd).
> И это (ls -1f) занимает меньше минуты на md raid5 из 4х sata-2 дисков.
Да, а ещё вы 11 млн. раз сделали бы тяжелый exec на бинарник rm вместо простого сисколла unlink
> Насколько rsync быстрее получается?
Насколько именно быстрее выяснить не получилось. Все остальные способы банально падали по памяти.
Я просто по-strac-ил и не придумал, что можно выкинуть. Он там делает getdents, потом lstat на файл, потом unlink без переключений контекстов.
Соответственно, ему не нужно нигде хранить выхлоп lstat (а ls кладет в память результаты lstat на каждый файл в память, при этом, собственно, сначала делает lstat на каждый файл).
Ну а выхлоп getdents можно читать без всасывания всего массива в память. Да и там, емнип, словарь/массив из номеров inodes файлов, так что оно и так сильно меньше занимает.
> Он же сравнивает каталоги прежде чем синхронизировать…
Нет, не совсем так. Механику я выше описал.
Он строит «индекс» только для первого каталога (пустого в нашем случае) в памяти. Потом (ну при условии -a —delete, в остальных случаях может быть по другому) он работает пофайлово. Видит следующий файл в выхлопе getdents, смотрит на него, смотрит, что такого же файла (с тем же именем) нет в исходном каталоге, делает unlink, берет следующий файл из getdents
Опции —delete-before и —delete-after вот уже могут всасывать в память индексы двух каталогов, потому что в теории они там пригодились бы. Или, по крайней мере, rsync хранил бы в памяти инфу о том, какие файлы нужно удалить (если —after использовать), чтобы потом этот массив использовать. Но —delete точно ничего в память не кладет.
Собственно, если getdents не влазит в память — то такой каталог удалить уже в принципе ничем нельзя будет, кроме mkfs. Но там система уже упрется в 64-битность в каком-нибудь дурацком месте, а не в память, скорее.
Чувак ты сам херню несёшь. find+xargs не строит список, а лишь выплёвывает по каждому найденному файлу дальше (параметр print0, например) в xargs. Xargs же, на основе этого составляет свой список по 10-100 файлов (хз, сколько за раз) и просто удаляет. Если ты не умеешь работать с find — твои проблемы.
дополнительно запускать ionice для того, что бы следить за удалением файлов — о да, это круто!
а касательно раков: на высоко-нагруженных серверах любое лишнее увеличение IO это всегда плохо, любой overhead (в виде запуска ionice) вносит свои коррективы. И тут дело не в sata-дисках, а в том, что на таких серверах выполняются миллионы операций, и на каждую операцию много своих syscall’ов, lock’ов.
Тебе конечно пофиг, если база начала отвечать на 10 мс дольше, или даже на 100 мс, поэтому ты и админишь localhost
А теперь касательно ionice, который лишний десяток раз будет дёргать scheduler по типу «а можно ли выполнить это сейчас? а никому ли я не наврежу? и т.д.». Надо ли это на высоконагруженных серверах? Нет.
В целом точка зрения на быстрое удаление понятно. Но для информации:
6.36user 17.28system 1:57.59elapsed 20%CPU (0avgtext+0avgdata 22788maxresident)k
11726752inputs+0outputs (0major+11768minor)pagefaults 0swaps
Или мне кажется или ls -1f использует всего ничего памяти. Т.е. выпадение по памяти здесь весьма сомнительно.
> Xargs же, на основе этого составляет свой список по 10-100 файлов (хз, сколько за раз) и просто удаляет. Если ты не умеешь работать с find — твои проблемы.
Интересно, с каких пор утилита для распараллеливания научилась сама файлы удалять?
Удалять умеет find, но делает он это per-entry.
> Тебе конечно пофиг, если база начала отвечать на 10 мс дольше, или даже на 100 мс, поэтому ты и админишь localhost
да, пофиг, потому что у меня нет баз, которые нельзя отключать. Либо на них похуй всем (читай — девелопмент), либо есть ещё пара-тройка-десять таких баз (и на одну, опять же, всем насрать).
> если база начала отвечать на 10 мс дольше, или даже на 100 мс
Впрочем, если у тебя базы начинают отвечать на 10-100 мс дольше из-за того, что кто-то рядом елозит по дискам — i have bad news for you.
> А теперь касательно ionice, который лишний десяток раз будет дёргать scheduler
Ты точно понимаешь, как работает дефолтно ведущий себя дисковый шедуллинг в linux? Намекну — ionice это всего-лишь user-space утилита.
> Надо ли это на высоконагруженных серверах? Нет.
Поэтому у тебя на этих серверах FIFO-шедуллер уже включен?
> поэтому ты и админишь localhost
Да. localhost с желтой стрелкой на морде.
Anyway, не хочешь удалять быстро — не удаляй быстро. Только не пиши неправду, тебя гугл индексирует как бэ.
> Или мне кажется или ls -1f использует всего ничего памяти. Т.е. выпадение по памяти здесь весьма сомнительно.
Да, ls -1f действительно живет. Впрочем, что с этим выхлопом потом делать — непонятно. Если в xargs rm передавать, то это много-много тяжелых exec() на бинарник (пусть и бинарник этот в памяти). А хвостом будут всё те же stat() + unlink()