Przyspiesz kopiowanie 1000000 małych plików

11

Mam pliki 1000000 4-20 kb w reż. Muszę skopiować ten reż. Ale wydaje się, że muszę szukać każdego pliku, więc zajmuje to sporo czasu.

Czy jest sposób, aby przyspieszyć to?

Obecnie myślę, że gdybym mógł uzyskać bloki dyskowe zajmowane przez te pliki, mógłbym je posortować, scalić bloki, które były blisko (biorąc pod uwagę, że sekwencyjny odczyt jest często szybszy niż wyszukiwanie) i odczytać te bloki, aby były w pamięci RAM pamięć podręczna (mam 32 GB pamięci RAM) przed wykonaniem kopii.

Ale żeby to zadziałało, potrzebuję sposobu, aby określić, które bloki są na plikach.

Używam EXT4 na urządzeniu magnetycznym (tj. Nie SSD).

Edytować:

To powinno zadziałać, ale nie:

ls |
parallel -IOO --pipe "sudo parallel -j100 hdparm --fibmap {}'|tail -n +5'" |
sort -nk 2 | 
perl -ane 'if($u+10000 < $F[1]) { print "$l ",($u-$l),"\n"; $l=$F[1] } $u=$F[2]' |
sudo parallel --colsep ' ' dd if=/dev/sda1 skip={1} bs=512 count={2} '| cat >/dev/null'

Podczas testowania na dużym pliku plik nie jest buforowany.

Edycja2:

Oto kilka punktów odniesienia. Pamięć podręczna została opróżniona ( echo 3 >/proc/sys/vm/drop_caches) między każdym uruchomieniem. Pomiary wykonane za pomocą iostats -dkx 5.

rsync -Hav foo/ bar/: 1800 KB/s
cp -a foo/ bar/: 3600 KB/s
cat sort-by-inode | parallel -j1 -X cp foo/{} bar/: 5000 KB/s
cat sort-by-inode | shuf | parallel -j1 -X cp foo/{} bar/: 3000 KB/s
cat sort-by-inode | shuf | parallel -j10 -X cp foo/{} bar/: 7000 KB/s
cat sort-by-inode | parallel -j10 -X cp foo/{} bar/: 8000 KB/s
cat sort-by-inode | parallel -j100 -X cp foo/{} bar/: 9000 KB/s
cat sort-by-inode | parallel -j500 -X cp foo/{} bar/: 10000 KB/s

Czego możemy się z tego nauczyć?

Wygląda na to, że sortowanie według i-węzłów jest dobrym pomysłem. Ale wydaje się, że równoległe wielokrotne cpzwiększenie wydajności jeszcze bardziej. Warto podkreślić, że źródłem foo/jest dysk magnetyczny, więc to atakuje mit, że równoległe we / wy do pojedynczego wrzeciona nie przyspieszy we / wy: równoległe wyraźnie i konsekwentnie przyspiesza kopiowanie.

Ole Tange
źródło
Czy twój katalog zawiera tylko pliki? Czy Twoja lokalizacja docelowa znajduje się w tym samym systemie plików?
Joseph R.
Aby uzyskać dokładne polecenie, którego używasz do kopiowania? Coś jak cp -r /mnt/dir1 /mnt/dirdestlub coś takiego cp /mnt/dir1/* /mnt/dirdest?
maxschlepzig
Tylko pliki, ale nie ten sam system plików: cp -r / mnt / dir1 / mnt2 / dirdest
Ole Tange
btw, nie sądzę, że to pomaga, jeśli równolegle wykonujesz dostęp do dysku twardego, gdy chcesz zminimalizować liczbę wyszukiwań dysku.
maxschlepzig
Napisałem program, który porządkuje pliki według liczby ich zasięgu (bardziej prawdopodobne jest wystąpienie na dysku) tutaj: github.com/nh2/diskorder
nh2

Odpowiedzi:

9

Przy założeniu, że

  • wpisy zwrócone przez readdir nie są sortowane według numeru i-węzła
  • odczyt plików w kolejności i-węzłów zmniejsza liczbę operacji wyszukiwania
  • zawartość większości plików znajduje się w początkowej alokacji 8k (optymalizacja ext4), co również powinno dać mniej operacji wyszukiwania

możesz spróbować przyspieszyć kopiowanie poprzez kopiowanie plików w kolejności i-węzłów.

Oznacza to użycie czegoś takiego:

$ cd /mnt/src
$ ls -U -i | sort -k1,1 -n | cut -d' ' -f2- > ~/clist
$ xargs cp -t /mnt2/dst < ~/clist
maxschlepzig
źródło
@mikeserv, co masz na myśli? ls -Uto za mało, ponieważ nie sortuje według numerów i-węzłów ... i dlaczego miałbym chcieć -1?
maxschlepzig
@mikeserv, „w kolejności katalogów” to nie to samo, co kolejność i-węzłów! Gdyby tak było, nie musiałbyś do tego używać innego słowa. To, co uważasz za dziwne, nie ma znaczenia. Testowałem go nawet na systemie plików ext4. I tam kolejność katalogów rzeczywiście różni się od kolejności i-węzłów. -1wyświetla tylko „jeden plik w wierszu” - nie pomaga w przypadku nowych wierszy w nazwach plików. Do tego możesz użyć find -print0/xargs -O.
maxschlepzig
@mikeserv, o czym ty mówisz? Przykład licznika: mkdir tmp; cd tmp; touch foo"<RETURN>"bar; lswypisuje „foo? Bar”. ls -1Również 'foo? Bar' odbitek. A ls -1 | wc -ldrukuje '2'. A find -lsdrukuje nazwy pliku jako './foo\nbar. A cp -i ls -1` x` kończy się niepowodzeniem z „cp: target” x ”nie jest katalogiem”.
maxschlepzig
Cholera - uczysz mnie na prawo i lewo! -qrobi to, co myślałem -1, że zrobię ! Jeszcze raz przepraszam - nie wspominając o podziękowaniach.
mikeserv
4

GNU tar- zgodnie z paxtradycją - samodzielnie obsługuje łącza twarde.

cd "$srcdir" ; tar --hard-dereference -cf - ./* |
    tar -C"${tgtdir}" -vxf -

W ten sposób masz tylko dwa tarprocesy i nie musisz ciągle powoływać cpsię.

mikeserv
źródło
2

W podobnym tonie do użytkownika @ maxschlepzig odpowiedź, można analizować dane wyjściowe filefragdo plików sortowane w kolejności ich pierwsze fragmenty pojawiają się na dysku:

find . -maxdepth 1 -type f |
  xargs -d'\n' filefrag -v |
  sed -n '
    /^   0:        0../ {
      s/^.\{28\}\([0-9][0-9]*\).*/\1/
      h
      }
    / found$/ {
      s/:[^:]*$//
      H
      g
      s/\n/ /p
      }' |
    sort -nk 1,1 |
    cut -d' ' -f 2- |
    cpio -p dest_dir

MMV z powyższym sedskryptem, więc należy dokładnie przetestować.

W przeciwnym razie cokolwiek zrobisz filefrag(część e2fsprogs) będzie znacznie szybsze w użyciu, niż hdparmmoże wymagać wielu argumentów pliku. Samo obciążenie związane z uruchomieniem hdparm1 000 000 razy spowoduje znaczne obciążenie.

Również prawdopodobnie nie byłoby tak trudno napisać perlskrypt (lub program C), FIEMAP ioctldla każdego pliku, utworzyć posortowaną tablicę bloków, które należy skopiować, a pliki należy do, a następnie skopiować wszystko w kolejności według odczytanie rozmiaru każdego bloku z odpowiedniego pliku (uważaj, aby nie zabrakło deskryptorów plików).

Graeme
źródło
Jest to miłe, zobacz także home.ifi.uio.no/paalh/publications/files/ipccc09.pdf w dokumencie, który opisuje podejście i pokazuje przyspieszenie ~ 4x tardla ich plików.
nh2
1
Wysłałem e-mailem do autorów artykułu z pytaniem, czy mogą wydać qtarjako open source; jest teraz na github.com/chlunde/qtar
nh2