Miliony (małych) plików tekstowych w folderze

15

Chcielibyśmy przechowywać miliony plików tekstowych w systemie plików Linux, aby móc spakować i udostępnić dowolną kolekcję jako usługę. Wypróbowaliśmy inne rozwiązania, takie jak baza danych kluczy / wartości, ale nasze wymagania dotyczące współbieżności i równoległości sprawiają, że korzystanie z macierzystego systemu plików jest najlepszym wyborem.

Najprostszym sposobem jest przechowywanie wszystkich plików w folderze:

$ ls text_files/
1.txt
2.txt
3.txt

co powinno być możliwe w systemie plików EXT4 , który nie ma ograniczenia liczby plików w folderze.

Dwa procesy FS będą następujące:

  1. Napisz plik tekstowy ze złomowania w Internecie (liczba plików w folderze nie powinna mieć wpływu).
  2. Spakuj wybrane pliki według listy nazw plików.

Moje pytanie brzmi: czy przechowywanie do dziesięciu milionów plików w folderze wpłynie na wydajność powyższych operacji lub ogólną wydajność systemu, inaczej niż tworzenie drzewa podfolderów dla plików, w których będą żyć?

użytkownik1717828
źródło
4
Powiązane: Jak naprawić sporadyczne błędy „Brak miejsca na urządzeniu” podczas mv, gdy urządzenie ma dużo miejsca . Używanie dir_index, które często jest domyślnie włączone, przyspieszy wyszukiwanie, ale może ograniczyć liczbę plików w katalogu.
Mark Plotnick,
Dlaczego nie spróbować szybko na maszynie wirtualnej i zobaczyć, jak to jest? Dzięki bash wypełnianie folderu milionami plików tekstowych zawierających losowe znaki jest banalne. Wydaje mi się, że w ten sposób otrzymasz naprawdę przydatne informacje, oprócz tego, czego się tutaj nauczysz.
JoshuaD
2
@JoshuaD: Jeśli zapełnisz wszystko naraz na świeżym FS, prawdopodobnie będziesz mieć wszystkie i-węzły sąsiadujące na dysku, więc ls -lwszystko inne, statco jest każdym i-węzłem w katalogu (np. bashGlobbing / tabulacja), będzie sztucznie szybsze niż po pewnym zużyciu (usuń niektóre pliki, napisz nowe). ext4 może to zrobić lepiej niż XFS, ponieważ XFS dynamicznie przydziela miejsce dla i-węzłów vs. danych, więc myślę, że możesz skończyć z bardziej rozproszonymi i-węzłami. (Ale to tylko domysły oparte na bardzo małej szczegółowej wiedzy; ledwo używałem ext4). Idź z abc/def/podkatalogami.
Peter Cordes,
Tak, nie sądzę, aby test, który zasugerowałem, byłby w stanie powiedzieć OP „to zadziała”, ale zdecydowanie mógłby szybko powiedzieć mu „to nie zadziała”, co jest przydatne.
JoshuaD,
1
ale nasze wymagania dotyczące współbieżności i równoległości sprawiają, że używanie natywnego systemu plików najlepszym wyborem. Co próbowałeś? Od razu pomyślałem, że nawet niższej klasy RDBMS, taki jak MySQL i serwlet Java, który tworzy pliki zip w locieZipOutputStream , pokonałby prawie każdy wolny rodzimy system plików Linux - wątpię, czy chcesz zapłacić za GPFS IBM. Pętla przetwarzająca zestaw wyników JDBC i sprawiająca, że ​​strumień zip to prawdopodobnie zaledwie 6-8 linii kodu Java.
Andrew Henle,

Odpowiedzi:

10

lsPolecenia TAB nawet uzupełnianie lub symbole ekspansji przez powłokę, zwykle przedstawić wyniki w celu alfanumerycznej. Wymaga to przeczytania całego wykazu katalogów i posortowania go. Mając dziesięć milionów plików w jednym katalogu, ta operacja sortowania zajmie nie bez znaczenia czas.

Jeśli możesz się oprzeć pokusie ukończenia TAB i np. Napisać nazwy plików do skompresowania w całości, nie powinno być problemów.

Innym problemem związanym z symbolami wieloznacznymi może być rozszerzenie symboli wieloznacznych, które może powodować powstanie większej liczby nazw plików niż mieści się w wierszu polecenia o maksymalnej długości. Typowa maksymalna długość wiersza poleceń będzie więcej niż wystarczająca w większości sytuacji, ale kiedy mówimy o milionach plików w jednym katalogu, nie jest to już bezpieczne założenie. Gdy maksymalna długość wiersza poleceń zostanie przekroczona przy interpretacji symboli wieloznacznych, większość powłok po prostu zawiedzie cały wiersz poleceń bez jego wykonania.

Można to rozwiązać, wykonując operacje wieloznaczne za pomocą findpolecenia:

find <directory> -name '<wildcard expression>' -exec <command> {} \+

lub podobną składnię, gdy tylko jest to możliwe. find ... -exec ... \+Automatycznie uwzględniać długość linii poleceń maksymalna i wykona polecenie tyle razy, ile wymagane podczas montażu maksymalną ilość nazw do każdego wiersza poleceń.

telcoM
źródło
Nowoczesne systemy plików używają drzew B, B + lub podobnych do przechowywania wpisów w katalogu. en.wikipedia.org/wiki/HTree
dimm
4
Tak ... ale jeśli powłoka lub lspolecenie nie dowie się, że lista katalogów jest już posortowana, i tak poświęcą trochę czasu na uruchomienie algorytmu sortowania. Poza tym przestrzeń użytkownika może używać zlokalizowanego porządku sortowania (LC_COLLATE), który może różnić się od tego, co system plików może robić wewnętrznie.
telcoM,
17

Jest to niebezpiecznie zbliżone do opartego na opiniach pytania / odpowiedzi, ale postaram się przedstawić kilka faktów w moich opiniach.

  1. Jeśli masz bardzo dużą liczbę plików w folderze, każda operacja oparta na powłoce, która próbuje je wyliczyć (np. mv * /somewhere/else), Może się nie powieść z powodzeniem, lub wynik może być zbyt duży do użycia.
  2. ls wyliczenie bardzo dużej liczby plików potrwa dłużej niż niewielka liczba plików.
  3. System plików będzie w stanie obsłużyć miliony plików w jednym katalogu, ale ludzie prawdopodobnie będą mieli problemy.

Jedną z rekomendacji jest podzielenie nazwy pliku na dwie, trzy lub cztery znaki i użycie ich jako podkatalogów. Na przykład somefilename.txtmoże być przechowywany jako som/efi/somefilename.txt. Jeśli używasz nazw numerycznych, podziel je od prawej do lewej zamiast od lewej do prawej, aby uzyskać bardziej równomierny rozkład. Na przykład 12345.txtmoże być przechowywany jako 345/12/12345.txt.

Możesz użyć odpowiednika opcji, zip -j zipfile.zip path1/file1 path2/file2 ...aby uniknąć dołączania pośrednich ścieżek podkatalogów do pliku ZIP.

Jeśli serwujesz te pliki z serwera WWW (nie jestem do końca pewien, czy to istotne), ukrywanie tej struktury na korzyść katalogu wirtualnego z regułami przepisywania w Apache2 jest banalne. Zakładam, że to samo dotyczy Nginx.

roaima
źródło
*Ekspansja uda, chyba że zabraknie pamięci, ale chyba podwyższyć limit stacksize (Linux) lub zastosować powłokę gdzie mvjest wbudowane lub mogą być wbudowane (ksh93, zsh), przy czym execve()funkcja systemowa może zakończyć się niepowodzeniem z błędem E2BIG.
Stéphane Chazelas,
@ StéphaneChazelas tak ok, mój wybór słów mógł być lepszy, ale efekt netto dla użytkownika jest taki sam. Zobaczę, czy mogę nieznacznie zmienić słowa, nie pogrążając się w złożoności.
roaima
Po prostu ciekawy, jak rozpakowałbyś ten plik zip, jeśli unikniesz dołączania do niego pośrednich ścieżek podkatalogu, bez wpadania na omawiane problemy?
Ośmiornica
1
@Octopus OP stwierdza, że ​​plik zip będzie zawierał „ wybrane pliki, podane według listy nazw plików ”.
roaima,
Polecam używanie zip -j - ...i przesyłanie strumienia wyjściowego bezpośrednio do połączenia sieciowego klienta zip -j zipfile.zip .... Zapisanie rzeczywistego pliku zip na dysku oznacza, że ​​ścieżka danych jest odczytywana z dysku-> kompresuj-> zapisuj na dysk-> czytaj z dysku-> wysyłaj do klienta. To może nawet trzykrotnie zwiększyć wymagania IO dysku w porównaniu z odczytem z dysku-> kompresuj-> wysyłaj do klienta.
Andrew Henle,
5

Prowadzę stronę internetową, która obsługuje bazę danych filmów, programów telewizyjnych i gier wideo. Dla każdego z nich jest wiele obrazów z telewizorem zawierającym dziesiątki obrazów na program (np. Migawki odcinków itp.).

W końcu jest dużo plików graficznych. Gdzieś w zakresie ponad 250 000. Wszystkie są przechowywane w zamontowanym blokowym urządzeniu magazynującym, w którym czas dostępu jest rozsądny.

Moja pierwsza próba zapisania zdjęć była w jednym folderze jako /mnt/images/UUID.jpg

Natknąłem się na następujące wyzwania.

  • lsprzez zdalny terminal po prostu się zawiesił. Proces poszedłby zombie i CTRL+Cnie złamałby go.
  • zanim dojdę do tego punktu, każde lspolecenie szybko zapełni bufor wyjściowy i CTRL+Cnie zatrzyma niekończącego się przewijania.
  • Skompresowanie 250 000 plików z jednego folderu zajęło około 2 godzin. Musisz uruchomić polecenie zip odłączone od terminala, w przeciwnym razie każda przerwa w połączeniu oznacza, że ​​musisz zacząć od nowa.
  • Nie ryzykowałbym próbą użycia pliku zip w systemie Windows.
  • Folder szybko stał się strefą niedozwoloną dla ludzi .

Skończyło się na tym, że musiałem przechowywać pliki w podfolderach, wykorzystując czas utworzenia do utworzenia ścieżki. Takich jak /mnt/images/YYYY/MM/DD/UUID.jpg. To rozwiązało wszystkie powyższe problemy i pozwoliło mi utworzyć pliki zip, które były kierowane na datę.

Jeśli jedynym identyfikatorem pliku, który masz, jest liczba, a te liczby mają tendencję do działania w sekwencji. Dlaczego nie grupa je 100000, 10000i 1000.

Na przykład, jeśli masz plik o nazwie 384295.txtścieżka to:

/mnt/file/300000/80000/4000/295.txt

Jeśli wiesz, osiągniesz kilka milionów. Użyj 0prefiksów dla 1 000 000

/mnt/file/000000/300000/80000/4000/295.txt
Reactgular
źródło
1

Napisz plik tekstowy ze złomowania w Internecie (liczba plików w folderze nie powinna mieć wpływu).

Aby utworzyć nowy plik, należy przeskanować plik katalogu w poszukiwaniu wystarczającej ilości wolnego miejsca na nowy wpis katalogu. Jeśli nie zostanie znalezione wystarczająco duże miejsce do zapisania nowego wpisu katalogu, zostanie ono umieszczone na końcu pliku katalogu. Wraz ze wzrostem liczby plików w katalogu rośnie także czas skanowania katalogu.

Tak długo, jak pliki katalogów pozostają w pamięci podręcznej systemu, nie będzie to miało negatywnego wpływu na wydajność, ale jeśli dane zostaną zwolnione, odczytanie pliku katalogu (zwykle bardzo rozdrobnionego) z dysku może zająć sporo czasu. Dysk SSD poprawia to, ale w przypadku katalogu z milionami plików nadal może wystąpić zauważalny spadek wydajności.

Spakuj wybrane pliki według listy nazw plików.

Może to również wymagać dodatkowego czasu w katalogu z milionami plików. W systemie plików z hashowanymi pozycjami katalogu (jak EXT4) różnica ta jest minimalna.

czy przechowywanie do dziesięciu milionów plików w folderze wpłynie na wydajność powyższych operacji lub ogólną wydajność systemu w inny sposób niż utworzenie drzewa podfolderów dla plików, w których będą przechowywane?

Drzewo podfolderów nie ma żadnej z powyższych wad wydajności. Ponadto, jeśli podstawowy system plików zostanie zmieniony tak, aby nie miał zaszyfrowanych nazw plików, metodologia drzewa nadal będzie działać dobrze.

Piotr
źródło
1

Po pierwsze: zapobiegaj sortowaniu „ls” za pomocą „ls -U”, może zaktualizuj swój ~ / bashrc tak, aby miał „alias ls =" ls -U "lub podobny.

W przypadku dużego zestawu plików możesz wypróbować to w następujący sposób:

  • utwórz zestaw plików testowych

  • sprawdź, czy wiele nazw plików powoduje problemy

  • użyj xargs parmeter-batching i zip (domyślne) zachowanie dodawania plików do zip, aby uniknąć problemów.

To działało dobrze:

# create ~ 100k files
seq 1 99999 | sed "s/\(.*\)/a_somewhat_long_filename_as_a_prefix_to_exercise_zip_parameter_processing_\1.txt/" | xargs touch
# see if zip can handle such a list of names
zip -q /tmp/bar.zip ./*
    bash: /usr/bin/zip: Argument list too long
# use xargs to batch sets of filenames to zip
find . -type f | xargs zip -q /tmp/foo.zip
l /tmp/foo.zip
    28692 -rw-r--r-- 1 jmullee jmullee 29377592 2017-12-16 20:12 /tmp/foo.zip
jmullee
źródło