1000000 개의 작은 파일 복사 속도 향상


11

디렉토리에 1000000 4-20 kb 파일이 있습니다. 그 디렉토리를 복사해야합니다. 그러나 각 파일을 찾아야하므로 시간이 오래 걸립니다.

속도를 높일 수있는 방법이 있습니까?

나는 현재이 파일들이 차지하는 디스크 블록을 얻을 수 있다면, 그것들을 정렬하고, 가까운 블록을 병합하고 (순차적 읽기가 종종 추구하는 것보다 빠릅니다) 블록을 읽고 RAM에 있도록 할 수 있다고 생각합니다 복사하기 전에 캐시 (32GB RAM이 있음).

그러나 그것이 작동하려면 파일이있는 블록을 식별하는 방법이 필요합니다.

자기 장치에서 EXT4를 사용하고 있습니다 (예 : SSD가 아님).

편집하다:

이것은 작동해야하지만 작동하지 않습니다.

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'

큰 파일에서 테스트 할 때는 파일을 캐시하지 않습니다.

편집 2 :

다음은 몇 가지 벤치 마크입니다. echo 3 >/proc/sys/vm/drop_caches각 실행 사이에 캐시가 플러시되었습니다 ( ). 로 측정 완료 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

그래서 우리는 그로부터 무엇을 배울 수 있습니까?

inode를 기준으로 정렬하는 것이 좋습니다. 그러나 여러 개의 병렬 처리 cp를 수행하면 성능이 더욱 향상됩니다. 소스 foo/가 자기 디스크라는 점을 강조 할 가치가 있으므로, I / O를 단일 스핀들로 병렬화하면 I / O 속도가 빨라지지 않는다는 신화를 공격 할 수 있습니다.


디렉토리에 파일 만 포함되어 있습니까? 대상 위치가 동일한 파일 시스템에 있습니까?
Joseph R.

정확한 명령으로 복사에 사용하고 있습니까? 뭔가 cp -r /mnt/dir1 /mnt/dirdest또는 비슷한 것 cp /mnt/dir1/* /mnt/dirdest?
maxschlepzig

파일은 같지만 파일 시스템은 동일하지 않음 : cp -r / mnt / dir1 / mnt2 / dirdest
Ole Tange

btw, 디스크 탐색을 최소화하려고 할 때 하드 디스크 액세스를 병렬로 실행하면 도움이되지 않는다고 생각합니다.
maxschlepzig

답변:


9

그것을 가정

  • 에서 반환 한 항목 readdir은 inode 번호로 정렬되지 않습니다
  • inode 순서로 파일을 읽으면 탐색 작업 수가 줄어 듭니다.
  • 대부분의 파일의 내용은 초기 8k 할당 (ext4 최적화)에 있으며 탐색 작업이 적습니다.

inode 순서로 파일을 복사하여 복사 속도를 높일 수 있습니다.

이것은 다음과 같은 것을 사용하는 것을 의미합니다.

$ cd /mnt/src
$ ls -U -i | sort -k1,1 -n | cut -d' ' -f2- > ~/clist
$ xargs cp -t /mnt2/dst < ~/clist

@ mikeserv, 무슨 뜻인가요? ls -Uinode 번호로 정렬하지 않기 때문에 충분하지 않습니다 ... 왜 내가 -1원합니까?
maxschlepzig

@mikeserv, 'in directory order'는 inode 순서와 다릅니다! 이 경우에는 다른 단어를 사용할 필요가 없습니다. 이상한 것을 발견하면 관련이 없습니다. 심지어 ext4 파일 시스템에서 테스트했습니다. 그리고 디렉토리 순서는 실제로 inode 순서와 다릅니다. -1'한 줄에 하나의 파일'만 나열하면 파일 이름의 줄 바꿈에 도움이되지 않습니다. 이를 위해을 사용할 수 있습니다 find -print0/xargs -O.
maxschlepzig

@ mikeserv, 무슨 소리 야? 카운터 예 : mkdir tmp; cd tmp; touch foo"<RETURN>"bar; ls'foo? bar'를 인쇄합니다. A ls -1는 'foo? bar'도 인쇄합니다. A ls -1 | wc -l는 '2'를 인쇄합니다. A find -ls는 파일 이름을 './foo\nbar'로 인쇄합니다. cp -i LS -1` x`는 'CP : 대상'실패 X '디렉토리가 아니다'.
maxschlepzig

젠장-당신은 저를 좌우로 가르치고 있습니다! -q내가 생각했던 -1것을한다! 다시 한번, 사과드립니다-감사합니다.
mikeserv

4

GNU tar-에서 pax자체 핸들의 하드 링크 - 전통.

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

이렇게하면 두 개의 tar프로세스 만 있으며 계속 cp반복 해서 호출 할 필요가 없습니다 .


2

@maxschlepzig의 대답 과 비슷한 맥락에서 filefrag파일의 첫 번째 조각이 디스크에 나타나는 순서대로 출력을 구문 분석 할 수 있습니다 .

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

위의 sed스크립트 가 포함 된 MMV 이므로 철저히 테스트하십시오.

그렇지 않으면, 당신이 무엇이든 filefrag(의 일부 e2fsprogs) hdparm여러 파일 인수를 취할 수있는 것보다 사용 속도가 훨씬 빠릅니다 . hdparm1,000,000 번 실행하는 오버 헤드 만으로도 많은 오버 헤드가 발생합니다.

또한 각 파일에 대해 perl스크립트 (또는 C 프로그램)를 FIEMAP ioctl작성하고 복사 해야하는 블록과 정렬 된 블록의 정렬 된 배열을 만든 다음 모든 것을 순서대로 복사하는 것이 어렵지 않을 것입니다. 해당 파일에서 각 블록의 크기를 읽습니다 (파일 설명자가 부족하지 않도록주의하십시오).


접근 방식을 설명 하고 파일 속도가 ~ 4 배 빨라지 는 논문 은 home.ifi.uio.no/paalh/publications/files/ipccc09.pdf 를 참조하십시오 tar.
nh2

1
나는이 논문의 저자들에게 전자 메일 qtar로 공개 소스로 배포 할 수 있는지를 이메일로 보냈다 . 그것은 지금 github.com/chlunde/qtar에 있습니다
nh2
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.