1,000,000개의 작은 파일 복사 속도 향상

1,000,000개의 작은 파일 복사 속도 향상

내 디렉토리에 1000,000개의 4-20kb 파일이 있습니다(이와 유사한 파일을 생성할 수 있습니다 seq 10000 | gzip > a; seq 1000000 | parallel --bar 'head -c{=$_=int(rand()*16)+4=}k a > {}':)

. 이 디렉토리를 복사해야 합니다. 그런데 파일을 일일이 검색해야 하는 것 같아서 시간이 꽤 걸립니다.

속도를 높일 수 있는 방법이 있나요?

현재 이러한 파일이 차지하는 디스크 블록을 얻을 수 있다면 파일을 정렬하고 가까운 블록을 병합하고(순차 읽기가 일반적으로 탐색보다 빠르다는 점을 고려하여) 블록을 읽어서 RAM 캐싱에 포함되도록 할 수 있다고 생각하고 있습니다. 복사본(저는 32GB RAM을 가지고 있습니다).

하지만 이를 달성하려면 파일이 있는 블록을 식별할 수 있는 방법이 필요합니다.

저는 자기 장치(즉, SSD가 아님)에서 EXT4를 사용하고 있습니다.

편집하다:

이는 작동하지만 작동하지 않습니다.

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 속도가 빨라지지 않는다는 통념이 깨졌습니다. 여기에서 명시적이고 일관되게 병렬화하면 복제 속도가 빨라질 수 있습니다.

답변1

우리가 말하면

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

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

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

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

답변2

tar전통적으로 GNU는 pax하드 링크 자체를 처리합니다.

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

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

답변3

비슷하게작성자: @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

MMV에는 위의 스크립트가 포함되어 있으므로 sed철저하게 테스트해 보시기 바랍니다.

그렇지 않으면 무엇을 하든 (의 일부)는 여러 파일 인수를 사용할 수 있는 것보다 훨씬 빠르게 filefrag사용됩니다 . 1,000,000번 실행하는 오버헤드만으로도 많은 오버헤드가 추가됩니다.e2fsprogshdparmhdparm

perl또한 FIEMAP ioctl각 파일에 대해 복사해야 할 청크와 해당 청크가 속한 파일의 정렬된 배열을 생성한 다음 모든 것을 순서대로 복사하고 각 청크를 읽는 스크립트(또는 C 프로그램)를 작성하는 것은 그리 어렵지 않을 수 있습니다. 해당 파일 크기(단, 파일 설명자가 부족하지 않도록 주의하세요)

관련 정보