Tło: serwer fizyczny, około dwóch lat, dyski SATA 7200 obr./min podłączone do karty RAID 3Ware, noatime montowany przez ext3 FS i dane = zamówione, nie pod szalonym obciążeniem, jądro 2.6.18-92.1.22.el5, czas pracy 545 dni . Katalog nie zawiera żadnych podkatalogów, tylko miliony małych (~ 100 bajtów) plików, a niektóre większe (kilka KB).
Mamy serwer, który w ciągu ostatnich kilku miesięcy trochę poszedł na kukułkę, ale zauważyliśmy go dopiero wtedy, gdy zaczął nie móc pisać do katalogu z powodu zbyt dużej liczby plików. W szczególności zaczął rzucać ten błąd w / var / log / messages:
ext3_dx_add_entry: Directory index full!
Na dysku tym pozostało wiele i-węzłów:
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sda3 60719104 3465660 57253444 6% /
Zgaduję, że to oznacza, że przekroczyliśmy limit liczby wpisów w samym pliku katalogu. Nie mam pojęcia, ile to plików, ale nie może to być, jak widać, więcej niż trzy miliony. Pamiętaj, że to nie jest dobre! Ale to pierwsza część mojego pytania: co to za górna granica? Czy można go przestroić? Zanim zacznę na mnie krzyczeć - chcę to wyciszyć ; ten ogromny katalog spowodował wiele problemów.
W każdym razie wyśledziliśmy problem w kodzie, który generował wszystkie te pliki, i naprawiliśmy go. Teraz utknąłem w usuwaniu katalogu.
Kilka opcji tutaj:
rm -rf (dir)
Najpierw tego spróbowałem. Zrezygnowałem i zabiłem go po półtora dnia bez widocznego uderzenia.
- unlink (2) w katalogu: Zdecydowanie warte rozważenia, ale pytanie brzmi, czy szybsze byłoby usunięcie plików w katalogu za pomocą fsck niż usunięcie za pomocą unlink (2). To znaczy w taki czy inny sposób muszę oznaczyć te i-węzły jako nieużywane. Zakłada się oczywiście, że mogę powiedzieć fsck, aby nie upuszczał wpisów do plików w / lost + found; w przeciwnym razie właśnie przeniosłem swój problem. Oprócz wszystkich innych obaw, po przeczytaniu o tym trochę więcej, okazuje się, że prawdopodobnie musiałbym wywołać niektóre wewnętrzne funkcje FS, ponieważ żaden z wariantów unlink (2), które mogę znaleźć, nie pozwoliłby mi po prostu beztrosko usunąć katalog z wpisami. Puchatek.
while [ true ]; do ls -Uf | head -n 10000 | xargs rm -f 2>/dev/null; done )
To jest właściwie skrócona wersja; prawdziwy, który uruchamiam, który po prostu dodaje raportowanie postępów i czyste zatrzymanie, gdy zabraknie plików do usunięcia, to:
eksport i = 0; time (while [true]; do ls -Uf | głowa -n 3 | grep -qF '.png' || przerwa; ls -Uf | głowa -n 10000 | xargs rm -f 2> / dev / null; eksport i = $ (($ i + 10000)); echo „$ i ...”; gotowy )
To wydaje się działać całkiem dobrze. Pisząc to, usunęło 260 000 plików w ciągu ostatnich trzydziestu minut.
- Jak wspomniano powyżej, czy można ograniczyć limit wpisów dla poszczególnych katalogów?
- Dlaczego usunięcie pojedynczego pliku, który był pierwszym z listy zwróconej przez
ls -U
, zajęło „prawdziwe 7m9.561s / użytkownik 0m0.001s / sys 0m0.001s” , a usunięcie pierwszych 10 000 wpisów za pomocą rozkaz w # 3, ale teraz idzie całkiem szczęśliwie? W tym przypadku usunął 260 000 w około trzydzieści minut, ale teraz zajęło kolejne piętnaście minut, aby usunąć kolejne 60 000. Dlaczego ogromne wahania prędkości? - Czy jest lepszy sposób na zrobienie czegoś takiego? Nie przechowuj milionów plików w katalogu; Wiem, że to głupie i nie zdarzyłoby się to na moim zegarku. Googlowanie problemu i przeglądanie SF i SO oferuje wiele wariantów
find
, które nie będą znacznie szybsze niż moje podejście z kilku oczywistych powodów. Ale czy pomysł usuwania przez fsck ma jakieś nogi? A może coś zupełnie innego? Nie mogę się doczekać, aby usłyszeć myślenie „po wyjęciu z pudełka” (lub w „mało znanym” pudełku).
Ostateczne wyjście skryptu !:
2970000...
2980000...
2990000...
3000000...
3010000...
real 253m59.331s
user 0m6.061s
sys 5m4.019s
Tak więc trzy miliony plików usunięto w nieco ponad cztery godziny.
rm -rfv | pv -l >/dev/null
. pv powinno być dostępne w repozytorium EPEL .