Mempercepat menyalin 10.00000 file kecil

11

Saya memiliki 1000000 4-20 kb file dalam direktori. Saya perlu menyalin dir itu. Tapi sepertinya saya harus melakukan pencarian untuk setiap file sehingga ini membutuhkan waktu yang cukup lama.

Apakah ada cara di mana saya dapat mempercepat ini?

Saat ini saya berpikir bahwa jika saya bisa mendapatkan blok disk yang ditempati file-file ini, saya bisa mengurutkannya, menggabungkan blok yang dekat (mengingat bahwa membaca berurutan sering lebih cepat daripada mencari) dan membaca blok ini, sehingga mereka berada dalam RAM cache (saya punya 32 GB RAM) sebelum melakukan copy.

Tetapi agar bisa berfungsi, saya perlu cara untuk mengidentifikasi blok mana file tersebut berada.

Saya menggunakan EXT4 pada perangkat magnetik (yaitu bukan SSD).

Edit:

Ini seharusnya bekerja tetapi tidak:

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'

Saat mengujinya pada file besar itu tidak men-cache file.

Sunting2:

Inilah beberapa tolok ukur. Cache memerah ( echo 3 >/proc/sys/vm/drop_caches) di antara setiap proses. Pengukuran dilakukan dengan 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

Jadi apa yang bisa kita pelajari dari itu?

Sepertinya mengurutkan berdasarkan inode adalah ide yang bagus. Tetapi tampaknya memaralelkan banyak cpmeningkatkan kinerja lebih jauh. Perlu ditekankan bahwa sumbernya foo/adalah cakram magnetik, jadi ini menyerang mitos bahwa memparalelkan I / O ke satu poros tidak akan mempercepat I / O: Memparalelkan dengan jelas dan konsisten mempercepat penyalinan di sini.

Ole Tange
sumber
Apakah direktori Anda hanya berisi file? Apakah lokasi target Anda pada sistem file yang sama?
Joseph R.
Untuk perintah persis yang Anda gunakan untuk menyalin? Sesuatu seperti cp -r /mnt/dir1 /mnt/dirdestatau sesuatu seperti cp /mnt/dir1/* /mnt/dirdest?
maxschlepzig
Hanya file tetapi bukan sistem file yang sama: cp -r / mnt / dir1 / mnt2 / dirdest
Ole Tange
btw, saya tidak berpikir itu membantu jika Anda menjalankan akses hard disk secara paralel ketika Anda ingin meminimalkan pencarian disk.
maxschlepzig
Saya menulis sebuah program yang memesan file dengan jumlah luasnya (lebih mungkin terjadi pada disk) di sini: github.com/nh2/diskorder
nh2

Jawaban:

9

Berasumsi bahwa

  • entri yang dikembalikan oleh readdirtidak diurutkan berdasarkan nomor inode
  • membaca file dalam urutan inode mengurangi jumlah operasi pencarian
  • konten sebagian besar file berada di alokasi 8k awal (optimasi ext4) yang juga harus menghasilkan operasi pencarian yang lebih sedikit

Anda dapat mencoba mempercepat penyalinan melalui penyalinan file dalam urutan inode.

Itu berarti menggunakan sesuatu seperti ini:

$ cd /mnt/src
$ ls -U -i | sort -k1,1 -n | cut -d' ' -f2- > ~/clist
$ xargs cp -t /mnt2/dst < ~/clist
maxschlepzig
sumber
@ mikeserv, apa maksudmu? ls -Utidak cukup karena tidak mengurutkan berdasarkan nomor inode ... dan mengapa saya harus mau -1?
maxschlepzig
@ mikeserv, 'dalam urutan direktori' tidak sama dengan urutan inode! Jika ini masalahnya, Anda tidak perlu menggunakan kata lain untuk ini. Apa yang Anda temukan aneh tidak relevan. Saya bahkan sudah mengujinya pada sistem file ext4. Dan di sana urutan direktori memang berbeda dari urutan inode. -1cukup cantumkan 'satu file per baris' - tidak membantu dengan baris baru dalam nama file. Untuk itu bisa Anda gunakan find -print0/xargs -O.
maxschlepzig
@ mikeserv, apa yang kamu bicarakan? Contoh Counter: mkdir tmp; cd tmp; touch foo"<RETURN>"bar; lsmencetak 'foo? Bar'. A ls -1juga mencetak 'foo? Bar'. A ls -1 | wc -lmencetak '2'. A find -lsmencetak nama file sebagai './foo\nbar'. Sebuah cp -i ls -1` x` gagal dengan 'cp: target 'x' bukan sebuah direktori'.
maxschlepzig
Sial - Anda mengajari saya kiri dan kanan! -qmelakukan apa yang saya pikir -1akan! Sekali lagi, permintaan maaf saya - belum lagi terima kasih.
mikeserv
4

GNU tar- dalam paxtradisi - menangani hardlink sendiri.

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

Dengan begitu Anda hanya memiliki dua tarproses dan Anda tidak perlu terus memohon cpberulang kali.

mikeserv
sumber
2

Pada nada yang mirip dengan jawaban @ maxschlepzig , Anda dapat menguraikan output filefraguntuk mengurutkan file dalam urutan fragmen pertama mereka muncul pada disk:

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 dengan sedskrip di atas , jadi pastikan untuk menguji secara menyeluruh.

Jika tidak, apa pun yang Anda lakukan, filefrag(bagian dari e2fsprogs) akan jauh lebih cepat digunakan daripada hdparmkarena dapat mengambil banyak argumen file. Hanya overhead menjalankan hdparm1.000.000 kali akan menambah banyak overhead.

Juga mungkin tidak akan terlalu sulit untuk menulis perlskrip (atau program C), FIEMAP ioctluntuk setiap file, membuat array yang diurutkan dari blok yang harus disalin dan file milik dan kemudian untuk menyalin semuanya dalam urutan oleh membaca ukuran setiap blok dari file yang sesuai (hati-hati jangan sampai kehabisan file deskriptor).

Graeme
sumber
Ini bagus, lihat juga home.ifi.uio.no/paalh/publications/files/ipccc09.pdf untuk makalah yang menjelaskan pendekatan dan menunjukkan percepatan ~ 4x taruntuk file-file mereka.
nh2
1
Saya telah mengirim email ke penulis makalah, menanyakan apakah mereka dapat dirilis qtarsebagai sumber terbuka; sekarang di github.com/chlunde/qtar
nh2