Dlaczego usuwanie plików z nazwy jest boleśnie powolne, a jednocześnie wyjątkowo szybkie?

11

Faux pas: Wspomniana poniżej metoda „szybka” nie jest 60 razy szybsza niż metoda powolna. Jest 30 razy szybszy. Będę winić błąd za godzinę (3 rano nie jest najlepszą porą dnia na jasne myślenie :) ..

Aktualizacja: dodałem podsumowanie czasów testu (poniżej).
Wydaje się, że istnieją dwa problemy związane ze współczynnikiem prędkości:

  • Wybór użytej komendy (porównania czasowe pokazano poniżej)
  • Charakter dużej liczby plików w katalogu ... Wygląda na to, że „duży jest zły”. Sprawy stają się coraz wolniej rosnące wraz ze wzrostem liczby.

Wszystkie testy zostały wykonane z 1 milionem plików.
(czasy rzeczywiste, użytkownika i sys podano w skryptach testowych)
Skrypty testowe można znaleźć na stronie paste.ubuntu.com

#
# 1 million files           
# ===============
#
#  |time   |new dir   |Files added in  ASCENDING order  
#  +----   +-------   +------------------------------------------------- 
#   real    01m 33s    Add files only (ASCENDING order) ...just for ref.
#   real    02m 04s    Add files, and make 'rm' source (ASCENDING order) 
#                      Add files, and make 'rm' source (DESCENDING order) 
#   real    00m 01s    Count of filenames
#   real    00m 01s    List of filenames, one per line
#   ----    -------    ------
#   real    01m 34s    'rm -rf dir'
#   real    01m 33s    'rm filename' via rm1000filesPerCall   (1000 files per 'rm' call)
#   real    01m 40s    'rm filename' via  ASCENDING algorithm (1000 files per 'rm' call)
#   real    01m 46s    'rm filename' via DESCENDING algorithm (1000 files per 'rm' call)
#   real    21m 14s    'rm -r dir'
#   real    21m 27s    'find  dir -name "hello*" -print0 | xargs -0 -n 1000 rm'
#   real    21m 56s    'find  dir -name "hello*" -delete'
#   real    23m 09s    'find  dir -name "hello*" -print0 | xargs -0 -P 0 rm'
#   real    39m 44s    'rm filename' (one file per rm call) ASCENDING
#   real    47m 26s    'rm filename' (one file per rm call) UNSORTED
#                                                       

Niedawno utworzyłem i usunąłem 10 milionów pustych plików testowych. Usuwając pliki według nazwy (tj. rm filename), Dowiedziałem się na własnej skórze, że istnieje ogromna różnica czasu między 2 różnymi metodami ...

Obie metody używają dokładnie tego samego rm filenamepolecenia.

Aktualizacja: jak się okazuje, polecenia nie były dokładnie takie same ... Jedno z nich wysyłało jednocześnie 1000 nazw plików do 'rm' ... To był problem z rozszerzaniem nawiasów klamrowych, w którym myślałem, że każda nazwa pliku jest zapisywana do pliku feeder w osobnej linii, ale tak naprawdę było to 1000 na linię

Nazwy plików są dostarczane przez „plik feeder” do while readpętli.
Plik feeder jest wyjściem ls -1 -f
Metody są identyczne we wszystkich aspektach, z wyjątkiem jednej rzeczy:

  • powoli metoda wykorzystuje niesegregowanych podajnika bezpośrednio z plikuls -1 -f
  • szybka metoda wykorzystuje posortowaną wersji tego samego pliku niesegregowanych

Nie jestem pewien, czy kwestia sortowania jest tutaj problemem, czy może jest tak, że posortowany plik podajnika po prostu pasuje do sekwencji, w której pliki zostały utworzone (użyłem prostego algorytmu rosnącej liczby całkowitej)

W przypadku 1 miliona plików metoda szybka rm filename jest 60 razy szybsza niż metoda powolna ... znowu nie wiem, czy to jest problem z sortowaniem, czy problem z tabelą skrótów za kulisami ... Podejrzewam nie jest to prosty problem z sortowaniem, ponieważ dlaczego miałbym ls -1 -fcelowo dać mi nieposortowaną listę świeżo dodanej „posortowanej” sekwencji nazw plików ...

Zastanawiam się tylko, co się tutaj dzieje, więc usunięcie następnych 10 milionów plików nie zajmuje mi dni (tak dni) :) .... Mówię „dni”, ponieważ próbowałem tylu alternatyw, a czasy zaangażowany wzrost disproportionatly do pliku numberof zaangażowany .. więc mam tylko przetestowane 1 mln w szczegółach

BTW: Usuwanie plików za pomocą „posortowanej listy” nazw jest faktycznie szybsze niż rm -rf2
- rm -rkrotnie i: było 30 razy wolniejsze niż metoda „posortowanej listy”

... ale czy problem jest tutaj „rozwiązany”? czy jest to bardziej związane z hashującą (lub jakąkolwiek inną) metodą przechowywania używaną przez ext4?

Rzeczą, która mnie dość zastanawia, jest to, że każde połączenie do rm filenamenie ma związku z poprzednim. (Przynajmniej tak jest z perspektywy „bash”)

Używam dysku Ubuntu / bash / 'ext4' / SATA II.

Peter.O
źródło
1
Robisz to źle! (tm) Słyszałeś kiedyś find -delete?
Alex
Twoje 2 testy rozpoczynają się w nierównych warunkach (nie udaję, że to jest rzeczywiście ważne): jeden odczytuje nazwy plików z pliku, a drugi odczytuje nazwy plików z pliku, który został utworzony (posortowany) bezpośrednio przed testem. Może być tak, że plik buforowany w drugim przypadku odtwarza niektóre (a może nie, kto wie). Aby testy były w bardziej wyrównanych warunkach, być może powinieneś zrobić prosty catdo świeżego pliku przed pierwszym testem - zamiast sortprzed drugim testem.
imz - Ivan Zakharyaschev
I zalecam, abyś przedstawił swoje spostrzeżenia i pytanie w bardziej przejrzysty sposób. Proszę, jedna rzecz na raz: porównaj tylko 2 przypadki w jednym pytaniu, przenieś dwa ważne przypadki na boisko, wszystkie pozostałe to tylko podstawowe informacje; proszę wyjaśnij to. Proszę nie mieszać kilku obserwacji w jednym poście.
imz - Ivan Zakharyaschev
Przedstawienie czasu systemowego i przestrzeni użytkownika może być również ważne dla rozwiązania zagadki, dlatego prosimy o uwzględnienie ich w pytaniu. Który z nich ma duże znaczenie w twoich testach?
imz - Ivan Zakharyaschev
1
Przedwczesna optymalizacja jest źródłem wszelkiego zła. :) Kiedy kiedykolwiek usuniesz 10 milionów plików? 100 000 na sekundę wydaje mi się wystarczająco szybka (aby zrujnować twój system).
użytkownik nieznany

Odpowiedzi:

2

Oczekuje się, że rm -r będzie powolny, ponieważ jest rekurencyjny. Najpierw należy wykonać głębokość przejścia w strukturze katalogów.

Jak utworzyłeś 10 milionów plików? czy użyłeś jakiegoś skryptu, który zapętla się w jakiejś kolejności? 1.txt, 2.txt, 3.txt ... jeśli tak, te pliki mogą być również przydzielone w tej samej kolejności w ciągłych blokach w hdd. Więc usuwanie w tym samym porządku będzie szybsze.

„ls -f” włączy -aU, która wyświetla listę w kolejności katalogów, która również jest rekurencyjna.

rajaganesh87
źródło
1
McAlot: Nie rozumiem, jak „rekurencyjne” miałoby znaczenie w tym przypadku , ponieważ nie ma w tym katalogu podkatalogów… Tak, użyłem „1.txt, 2.txt, 3.txt”. Być może istnieje kilka rzeczy wchodzą w interakcję: np. Dlaczego utworzenie 1 miliona plików zajmuje tylko 1min 30s, ale utworzenie 2 milionów zajmuje 7m 10s, a po ich usunięciu odtworzenie 1 miliona trwa znacznie dłużej (9m 30s), jest dziwne; wszystko działa powoli nagle. To się zdarzyło wcześniej. Myślę, że (?) usunięcie katalogu naprawiło go. Czy może jest w to zaangażowany demon pliku (nautilus; locate)?
Ciąg
Ogólnie rzecz biorąc, systemy plików nie są zoptymalizowane do obsługi dużej liczby plików w tym samym katalogu. Nie znam dokładnie ext4, ale w innych formatach wpisy katalogu zostały oznaczone jako nieużywane po usunięciu plików. Oznacza to, że nadal muszą być pomijane podczas wykonywania operacji w katalogu. To by wyjaśniało zachowanie, które widzisz.
KeithB
1
Usunąłem katalog „teraz wolniejszy” i użyłem innej nazwy dla nowego katalogu. Czas na utworzenie 1 miliona plików wrócił teraz do 1m 33s (w porównaniu do 9m 30s, gdy katalog „zawiera” 2 miliony usuniętych plików, pierwszy milion ma taką samą nazwę jak nowo dodany 1 milion) ... interesujący i to zgadza się z Twoim komentarzem „… właśnie oznaczonym jako nieużywany” … dotarcie tam; zaczyna mieć sens :)
Peter.O
@ fred.bear Mój zły, naprawdę nie znałem faktycznej hierarchii i moja odpowiedź była zgadywana. twój test w rzeczywistości akcentuje metadane, ale nie rzeczywiste pliki, ponieważ są to puste pliki. Najlepszym sposobem na przetestowanie tego rodzaju problemu jest pobranie plików z / var lub pamięci podręcznej serwera WWW. w każdym razie twój test również wydaje się interesujący, czy możesz spróbować usunąć dwie wymienione metody w różnych katalogach ... na przykład /sample1/1.txt,2.txt ... i /sample2/1.txt,2.txt ..
rajaganesh87
@ Mr.Confused.A.Lot ... Dzięki za pomoc. Twoje wyjaśnienie pomogło mi zrozumieć więcej na temat systemu plików i niektórych jego manier ... Mam teraz rozsądne wyobrażenie o przyczynach różnych problemów z prędkością ... niektóre były po prostu wyborem poleceń bash, a inne były po prostu problemami z systemem plików (
Zostało
2

Powinieneś zoptymalizować strukturę plików. Więc zamiast

for i in $(seq 1 1000); do touch file.$i; done

zrób coś mądrzejszego (zakłada bash):

function bucklocate() 
{ 
    hash=$(echo -n "$1"|md5sum|cut -f1); 
    echo -n "${hash:1:1}/${hash:7:1}/${hash:9:2}/$1"; 
}

hexdig="{0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f}"
eval mkdir -p $hexdig/$hexdig/$hexdig$hexdig


for i in $(seq 1 1000); do touch $(bucklocate file.$i); done

Teraz ten przykład jest raczej powolny z powodu użycia md5sum [1], użyj czegoś takiego jak poniżej, aby uzyskać znacznie szybszą odpowiedź, o ile nie potrzebujesz żadnych konkretnych nazw plików, duplikaty nie mają znaczenia i nie ma potrzeby powtarzalny skrót o określonej nazwie :)

mkdir -pv {0,1,2,3,4,5,6}/{0,1,2,3,4,5,6,7,8,9,10,12}
for  a in $(seq 1 100); do i=$RANDOM; echo touch "$(($i%7))/$(($i%13))/file.$i"; done

Oczywiście to wszystko niechlujnie zapożycza koncepcje z tablic skrótów

sehe
źródło
Myślę, że mówisz „używaj mniejszych katalogów” ... To ciekawy pomysł; rodzimy DBMS, który tworzy drzewo z grupy plików „bez drzewa”. Niektórzy mogą nazwać to planowaniem do przodu :) ... Jeśli to działa (i prawdopodobnie działa), to dobry pomysł ! :) ... Zaczynam rozumieć, że „duży jest zły”, gdy chodzi o liczbę plików w katalogu (przynajmniej dla ext4) ... Zaprezentowałeś obejście zapobiegawcze (+1), a ja ” powoli zaczynam
rozumieć,
Tak, przepraszam, że nie wyraziłem się jasno na temat pomniejszenia
reżimów