Jak usunąć miliony plików bez zakłócania działania serwera

11

Chciałbym usunąć katalog pamięci podręcznej nginx, który szybko wyczyściłem:

mv cache cache.bak
mkdir cache
service nginx restart

Teraz mam cache.bakfolder zawierający 2 miliony plików. Chciałbym go usunąć bez zakłócania pracy serwera.

Prosty rm -rf cache.bakwysyła serwer, nawet najprostsza odpowiedź HTTP zajmuje 16 sekund podczas działania rm, więc nie mogę tego zrobić.

Próbowałem ionice -c3 rm -rf cache.bak, ale to nie pomogło. Serwer ma dysk twardy, a nie dysk SSD, prawdopodobnie na dysku SSD może to nie stanowić problemu.

Uważam, że najlepszym rozwiązaniem byłoby ograniczenie przepustowości, tak jak działa wbudowany menedżer pamięci podręcznej nginx.

Jak byś to rozwiązał? Czy jest jakieś narzędzie, które może to dokładnie zrobić?

ext4 na Ubuntu 16.04

hyperknot
źródło
1
Jak udało ci się odzyskać z „rm -rf cache.bak”? Wygląda na to, że nginx działał podczas zmiany nazwy, więc mógł utrzymywać deskryptory plików, a nawet przełączyć się do nowego katalogu. Myślę, że musisz całkowicie zamknąć nginx, usunąć pamięć podręczną, a następnie uruchomić ponownie.
Jan Steinman
6
W przyszłości umieść pamięć podręczną w osobnym systemie plików. W ten sposób możesz po prostu nuke systemu plików, który jest znacznie szybszy niż próba usunięcia milionów plików. Nauczyłem się tego na własnej skórze kilka lat temu z katalogiem buforów hylafax zawierającym zilliony plików.
Dennis Kaarsemaker
Próbowałeś biegać rmużywając nicea ?
Vladislav Rastrusny
Spróbuj rsync, aby szybko usunąć - odpowiedzi na podobny przypadek - unix.stackexchange.com/questions/37329/…
kawu
Dzięki za wszystkie komentarze, podsumowałem moje ustalenia, aby napisać odpowiedź.
hyperknot,

Odpowiedzi:

9

Utwórz skrypt bash w następujący sposób:

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

Zapisz deleter.shna przykład z nazwą . Uruchom, chmod u+x deleter.shaby był wykonywalny.

Ten skrypt usuwa wszystkie pliki przekazane mu jako argumenty, a następnie śpi 0,5 sekundy.

Następnie możesz biegać

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

To polecenie pobiera listę wszystkich plików w pliku cache.bak i przekazuje pięć nazw plików jednocześnie do skryptu usuwania.

Możesz więc dostosować, ile plików jest usuwanych jednocześnie i jak długo występuje opóźnienie między każdą operacją usuwania.

Tero Kilkanen
źródło
Dzięki za to rozwiązanie, umieściłem je w moim ogólnym podsumowaniu. Jedno pytanie, jak sobie radzi z dużymi ns? Zwykle miałem problemy z * charakterem w dużych katalogach, które dawały błędy, prawda?
hyperknot
xargsrozumie maksymalny rozmiar wiersza poleceń i domyślnie próbuje go nie przekraczać. Ten ma dodatkowe limity nie więcej niż 5 ścieżek na raz.
BowlOfRed
1
Pamiętaj, że przy prędkości 10 plików na sekundę usunięcie 2 milionów plików zajmie 55 godzin.
Andrew Henle,
4

Powinieneś rozważyć zapisanie pamięci podręcznej w osobnym systemie plików, w którym możesz zamontować / odmontować, jak podano w komentarzach. Dopóki tego nie zrobisz, możesz użyć tej jednej linijki, /usr/bin/find /path/to/files/ -type f -print0 -exec sleep 0.2 \; -exec echo \; -deletezakładając, że Twój plik binarny znajduje się w / usr / bin i chcesz zobaczyć postęp na ekranie. Dostosuj odpowiednio sen, aby nie nadmiernie obciążać dysku twardego.

Alex
źródło
Nie trzeba -print0tutaj, ponieważ findnigdzie nie przesyłamy danych wyjściowych .
Tero Kilkanen
Być może interesuje Cię to, co się dzieje. Nazwij to paranoją, ale zawsze chcę mieć pewność, że usuwam właściwe pliki.
Alex
Ach, prawda, nie zdekodowałem polecenia poprawnie, moje złe.
Tero Kilkanen
3

Możesz wypróbować ionice na skrypcie pobierającym dane wyjściowe polecenia find. Coś w stylu:

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
)

W zależności od systemu plików każde usunięcie pliku może spowodować przepisanie całego katalogu. W przypadku dużych katalogów może to być hit. Wymagane są dodatkowe aktualizacje tabeli i-węzłów i ewentualnie lista wolnego miejsca.

Jeśli system plików ma kronikę, zmiany są zapisywane w kronice; stosowany; i usunięty z dziennika. Zwiększa to wymagania We / Wy dla intensywnej aktywności zapisu.

Możesz użyć systemu plików bez dziennika dla pamięci podręcznej.

Zamiast jonice możesz użyć komendy uśpienia, aby ograniczyć akcję. Działa to nawet wtedy, gdy nie działa jonice, ale usunięcie wszystkich plików zajmie dużo czasu.

BillThor
źródło
2

Otrzymałem tutaj wiele przydatnych odpowiedzi / komentarzy, które chciałbym podsumować, a także pokazać moje rozwiązanie.

  1. Tak, najlepszym sposobem, aby temu zapobiec , jest utrzymanie katalogu pamięci podręcznej w osobnym systemie plików. Nukowanie / szybkie formatowanie systemu plików zawsze zajmuje najwyżej kilka sekund (może minut), niezwiązanych z liczbą plików / katalogów w nim obecnych.

  2. Rozwiązania ionice/ nicenic nie zrobiły, ponieważ proces usuwania faktycznie spowodował prawie brak operacji we / wy. To, co spowodowało We / Wy, było moim zdaniem zapełnianiem się kolejek / buforów na poziomie jądra / systemu plików, gdy pliki były usuwane zbyt szybko przez proces usuwania.

  3. Sposób, w jaki go rozwiązałem, jest podobny do rozwiązania Tero Kilkanena, ale nie wymagał wywoływania skryptu powłoki. Użyłem wbudowanego --bwlimitprzełącznika rsync, aby ograniczyć szybkość usuwania.

Pełne polecenie było:

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

Teraz bwlimit określa przepustowość w kilobajach, która w tym przypadku dotyczyła nazwy pliku lub ścieżki plików. Ustawiając go na 1 KBps, usuwało około 100 000 plików na godzinę, czyli 27 plików na sekundę. Pliki miały względne ścieżki, takie jak cache.bak/e/c1/db98339573acc5c76bdac4a601f9ec1e, które mają 47 znaków, więc dawałoby to 1000/47 ~ = 21 plików na sekundę, więc trochę tak, jak przypuszczam 100 000 plików na godzinę.

Teraz dlaczego --bwlimit=1? Próbowałem różnych wartości:

  • 10000, 1000, 100 -> system zwalnia jak poprzednio
  • 10 -> system działa dość dobrze przez jakiś czas, ale powoduje częściowe spowolnienie raz na minutę. Czasy odpowiedzi HTTP nadal <1 sek.
  • 1 -> brak spowolnienia systemu. Nie spieszy mi się, a 2 miliony plików można usunąć w <1 dzień w ten sposób, więc wybrałem to.

Podoba mi się prostota wbudowanej metody rsync, ale to rozwiązanie zależy od względnej długości ścieżki. Nie jest to duży problem, ponieważ większość osób znalazłaby odpowiednią wartość metodą prób i błędów.

hyperknot
źródło
A teraz jestem ciekawy, jaki byłby efekt dysku, gdybyś zrobił coś takiego jak „mv cache.dir-old / dev / null”
ivanivan