Usuwanie milionów plików

38

Miałem katalog wypełniony milionami obrazów gif. Za dużo dla komendy rm.

Próbowałem polecenia find w następujący sposób:

find . -name "*.gif" -print0 | xargs -0 rm

Problem polega na tym, że bardzo źle psuje moją maszynę i powoduje przerwy dla klientów, ponieważ jest to serwer.

Czy jest jakiś sposób na szybsze usunięcie wszystkich tych plików ... bez blokowania urządzenia?

Corepuncher
źródło
Mam szybkość usuwania około 6 gb / h przy użyciu poniższego polecenia „nice find”. Prawdopodobnie zajmie to 48 godzin, aby pozbyć się wszystkich plików. Powodem tego był błąd skryptu b / ca, który nie powiódł się. Przekroczyłem „horyzont zdarzeń” za pomocą polecenia rm, a następnie uciekł
3
Czy usunięcie całego katalogu nie byłoby znacznie szybsze? Po prostu wyjmij „dobre” pliki, zanim nukujesz pozostałe ...
tucuxi
Cóż, każdy plik jest teraz zły, ponieważ został przeniesiony do / dir_old, a ja przerobiłem / dir. Ale czy rmdir nie napotka takich samych ograniczeń jak rm *?
@Corepuncher: Spodziewałbym się, że usunięcie całego katalogu (tak jak w przypadku rm -rfbyłoby szybsze. Warto spróbować.
Jason R
Obecnie uruchamiam „rm -rf” w katalogu. Działa już od ponad 20 minut ... bez zmiany rozmiaru dysku. Ale także nie zwrócił jeszcze automatycznie „zbyt długiej listy argumentów”. Jedynym problemem jest to, że naprawdę wbija mi się w maszynę i powoduje, że inne rzeczy stają się wolniejsze / nieudane. Nie jestem pewien, jak długo go puścić.

Odpowiedzi:

44

Szybsze niekoniecznie jest tym, czego chcesz. Możesz chcieć działać wolniej , więc usuwanie powoduje zubożenie mniejszej ilości zasobów podczas jego działania.

Użyj nice (1), aby obniżyć priorytet polecenia.

nice find . -name "*.gif" -delete

Dla procesów związanych z I / O nice (1) może nie być wystarczające. Harmonogram systemu Linux bierze pod uwagę operacje we / wy, a nie tylko procesor, ale możesz chcieć dokładniejszej kontroli nad priorytetem operacji we / wy.

ionice -c 2 -n 7 find . -name "*.gif" -delete

Jeśli to nie pomoże, możesz również spać, aby naprawdę spowolnić.

find . -name "*.gif" -exec sleep 0.01 \; -delete
John Kugelman wspiera Monikę
źródło
3
wow ... miliony plików z uśpieniem .1 s ... potrzebuje dnia na 864000 plików.
glglgl
7
@glglgl Dobra, mądra dupa. Zmieniłem limit czasu. :-P
John Kugelman popiera Monikę
28
Uśpienie może być dobrym wyborem, ale miło się nie przyda, ponieważ tutaj zadanie jest związane z IO, a nie z procesorem; zamiast tego możesz spróbować jonice. Zauważ, że jeśli sen jest zbyt mały, będzie bezużyteczny.
Matteo Italia,
3
@glglgl: chodzi o to, że jeśli nie chcesz powodować zakłóceń usługi na serwerze, musisz iść powoli, czas, w którym ten kod śpi, pozwala serwerowi na naprawdę przydatną pracę z dyskiem.
Matteo Italia,
1
+1 za sleepdodanie - miałem problemy z serwerami dławiącymi się na IO pomimo używania ionice -c 3. To znacznie
wydłuża
22

Ponieważ używasz Linuksa, a to zadanie prawdopodobnie wiąże się z operacjami we / wy, radzę nadać priorytet poleceniu bezczynnego harmonogramu operacji we / wy za pomocą ionice(1):

ionice -c3 find . -name '*.gif' -delete

W porównaniu do twojego oryginalnego polecenia, może nawet zaoszczędzić trochę więcej cykli procesora, unikając potoku do xargs.


źródło
@Braiam Co masz na myśli? To nie find ... -execma sensu.
O tak, przepraszam. Mój błąd. Jesteś pewien, że to jest skuteczne?
Braiam
1
Cóż, find(1)roszczenia dokumentacja tak. :) I powinno być oczywiste, że pozwolenie findsobie na usunięcie plików jest bardziej wydajne niż wykonanie rmpolecenia w tym celu.
1
Wypróbowałem kilka sugerowanych wersji w folderze z 4 milionami plików na serwerze produkcyjnym, a ta jest jedyną, która nie dusi systemu. ionice -c3obniża prio do uruchomienia, gdy IO jest bezczynne, w przeciwnym razie jest to idealne rozwiązanie. Zwróć uwagę, że ponieważ -deletenie jest to standardowe dla wyszukiwania, możesz zrobić to samo (włączając informację zwrotną, że to działa) za pomocą tego polecenia: ionice -c 3 find . -name '*.gif' -exec echo {} \; -exec rm {} \;- Powolne, ale nie ma żadnych ważnych procesów.
Christopher Lörken,
13

Nie.

Nie ma szybszego sposobu, odejdź od miękkiego formatu dysku. Pliki są przekazywane do rm jednocześnie (do limitu wiersza poleceń, może być również ustawiony na xargs), co jest znacznie lepsze niż wywoływanie rm na każdym pliku. Więc nie, zdecydowanie nie ma szybszego sposobu.

Używanie nice(lub reniceuruchomionego procesu) pomaga tylko częściowo, ponieważ służy to do planowania zasobów procesora , a nie dysku! A użycie procesora będzie bardzo niskie. Jest to słabość linuksa - jeśli jeden proces „zje” dysk (tj. Dużo z nim działa), cała maszyna utknie. Rozwiązaniem może być zmodyfikowane jądro do użytku w czasie rzeczywistym.

To, co zrobiłbym na serwerze, to ręczne zezwolenie innym procesom na wykonanie swojej pracy - w tym przerwy, aby serwer „oddychał”:

find . -name "*.gif" > files
split -l 100 files files.
for F in files.* do
    cat $F | xargs rm
    sleep 5 
done

Będzie to czekać 5 sekund po każdych 100 plikach. Zajmie to znacznie dłużej, ale Twoi klienci nie powinni zauważać żadnych opóźnień.

Tomas
źródło
„Pliki są podane do rm na raz (do wysokości linii poleceń” Więc gdy powłoka zostaje obciążona rm *, rozszerza *się w zgodzie z wszystkimi nazwami i przekazać go rm? To bardzo głupie. Dlaczego shell rozwinąć symbole wieloznaczne?
:-D @Joker_vD, żartujesz, jak sugeruje twoje imię? :-)
Tomas
2
@Joker_vD: Zgodność z decyzją Unix z 1970 roku. Windows tego nie robi. Tam programy mogą przekazywać symbole wieloznaczne do FindNextFile / FindNextFile, więc uzyskują wyniki pojedynczo.
MSalters
@Tomas Nie w tym przypadku. Szczerze mówiąc, od razu widzę 2 problemy z takim projektem: po pierwsze, linia poleceń nie jest gumowa; po drugie, program nie jest w stanie stwierdzić, czy został wywołany z, *ani nie /*podał w wątpliwość takiej decyzji użytkownika.
1
@Joker_vD Istnieje wiele dobrych rzeczy w powłoce wykonującej interpretację symboli wieloznacznych. Różni się od Windows, ale nie wyciągaj wniosku, że jest niesamowicie głupi tylko dlatego, że różni się od tego, do czego jesteś przyzwyczajony. Jeśli chcesz dowiedzieć się więcej, zachęcam do Google lub opublikowania pytania na odpowiedniej stronie Stack Exchange. To ogromne wykolejenie dla tego obszaru komentarzy.
John Kugelman wspiera Monikę
5

Jeśli liczba plików, które mają zostać usunięte, znacznie przewyższa liczbę pozostawionych plików, przejście do drzewa plików do usunięcia i wykonanie wszystkich aktualizacji systemu plików może nie być najbardziej efektywnym podejściem. (Jest to analogiczne do robienia niezręcznego zarządzania pamięcią z liczeniem odniesień, odwiedzania każdego obiektu w dużym drzewie w celu usunięcia odniesienia, zamiast przekształcania wszystkiego w śmieci w jednym kroku, a następnie przeglądania tego, co jest możliwe do wyczyszczenia.)

Oznacza to, że sklonuj części drzewa, które mają być przechowywane w innym tomie. Ponownie utwórz świeży, pusty system plików na oryginalnym woluminie. Skopiuj zachowane pliki z powrotem do ich oryginalnych ścieżek. Jest to nieco podobne do kopiowania śmieci .

Nastąpi pewien czas przestoju, ale może być lepszy niż ciągła zła wydajność i przerwy w świadczeniu usług.

Może to być niepraktyczne w twoim systemie i sytuacji, ale łatwo wyobrazić sobie oczywiste przypadki, w których jest to właściwy sposób.

Załóżmy na przykład, że chcesz usunąć wszystkie pliki w systemie plików. Po co powtarzać i usuwać jeden po drugim? Po prostu odmontuj go i wykonaj „mkfs” nad partycją, aby utworzyć pusty system plików.

A może chcesz usunąć wszystkie pliki oprócz kilku ważnych? Wydobądź stąd pół tuzina i ... „mkfs” na górze.

W końcu jest pewien próg rentowności, gdy jest wystarczająca liczba plików, które muszą zostać, że tańsze jest usuwanie rekurencyjne, biorąc pod uwagę inne koszty, takie jak wszelkie przestoje.

Kaz
źródło
4

Czy próbowałeś:

find . -name "*.gif" -exec rm {} +

Znak + na końcu spowoduje, że find będzie zawierać więcej plików do wykonania pojedynczej komendy rm. Sprawdź to pytanie, aby uzyskać więcej informacji.

Bartosz Firyn
źródło
Wykonuje się znacznie szybciej niż -print0 | Rozwiązanie xargs, ponieważ proces rm nie jest wywoływany dla każdego pliku, ale dla dużego zestawu i dlatego powoduje mniejsze obciążenie.
@JohnKugelman Masz rację, ale jest to rozszerzenie GNU, które nie zawsze jest dostępne w natywnej komendzie find .
CodeGnome,
OK, ciekawe, ale to jest całkiem nowa rzecz (jak również -delete), która nie zawsze musi tam być ..
Tomas
Z pewnością jednak nie przynosi to nic lepszego niż rozwiązanie PO.
Tomas