DistCp 가이드

DistCp 가이드

DistCp(distributed copy)는 대규모 클러스터 간/내 복사에 사용되는 도구예요. 분산, 오류 처리·복구, 보고에 MapReduce를 사용해요. 파일·디렉터리 목록을 map 태스크 입력으로 확장하며, 각 태스크는 소스 목록에 지정된 파일의 파티션을 복사해요.

출처: 문서

본문

개요 (Overview)

DistCp (distributed copy)는 대규모 클러스터 간/내 복사에 사용되는 도구예요. 그것의 분산, 오류 처리와 복구, 보고에 MapReduce를 사용해요. 파일·디렉터리 목록을 map 태스크 입력으로 확장하며, 각 태스크는 소스 목록에 지정된 파일의 파티션을 복사해요.

이전 DistCp 구현은 사용법, 확장성, 성능 모두에서 나름의 특이점과 단점이 있어요. DistCp 리팩터링의 목적은 이런 단점을 고쳐 프로그래밍 방식으로 사용·확장할 수 있게 하는 것이었어요. 런타임·설정 성능을 향상시키는 새 패러다임이 도입됐으며, 동시에 레거시 동작을 기본으로 유지해요. 이 문서는 새 DistCp의 설계, 그 새로운 기능, 최적 사용법, 그리고 레거시 구현과의 차이를 설명하는 것을 목표로 해요.

사용법 (Usage)

기본 사용법 (Basic Usage)

가장 일반적인 DistCp 호출은 클러스터 간 복사예요:

bash$ hadoop distcp hdfs://nn1:8020/foo/bar \
hdfs://nn2:8020/bar/foo

이것은 nn1의 /foo/bar 아래 네임스페이스를 임시 파일로 확장하고, 그 내용을 map 태스크 집합에 파티셔닝한 다음, 각 NodeManager에서 nn1에서 nn2로 복사를 시작해요. 명령줄에 여러 소스 디렉터리를 지정할 수도 있어요:

bash$ hadoop distcp hdfs://nn1:8020/foo/a \
hdfs://nn1:8020/foo/b \
hdfs://nn2:8020/bar/foo

또는 동등하게 -f 옵션으로 파일에서:

bash$ hadoop distcp -f hdfs://nn1:8020/srclist \
hdfs://nn2:8020/bar/foo

여기서 srclist는 다음을 포함해요:

hdfs://nn1:8020/foo/a
hdfs://nn1:8020/foo/b

여러 소스에서 복사할 때 두 소스가 충돌하면 DistCp는 오류 메시지와 함께 복사를 중단해요. 하지만 대상에서의 충돌은 지정된 옵션에 따라 해결돼요. 기본적으로 대상에 이미 존재하는 파일은 건너뛰어져요 (즉 소스 파일로 대체되지 않아요). 건너뛴 파일 수는 각 작업 끝에 보고되지만, 복사기가 일부 파일 집합에 실패했다가 나중 시도에서 성공했다면 부정확할 수 있어요.

각 NodeManager가 소스와 대상 파일시스템에 모두 도달하고 통신할 수 있는 것이 중요해요. HDFS의 경우 소스와 대상 모두 같은 버전의 프로토콜을 실행하거나 하위 호환 프로토콜을 사용해야 해요. 복사 후에는 소스와 대상의 목록을 생성해 교차 확인해 복사가 진짜 성공했는지 검증하는 것을 권장해요. DistCp는 Map/Reduce와 FileSystem API를 모두 사용하므로, 세 가지 중 하나의 문제가 복사에 조용히 악영향을 줄 수 있어요. 어떤 사람들은 -update를 활성화해 두 번째 패스를 수행해 성공을 거두기도 하지만, 사용자는 이를 시도하기 전에 그 의미를 충분히 알아야 해요. 또한 다른 클라이언트가 여전히 소스 파일에 쓰고 있다면 복사는 실패할 가능성이 높아요. 대상에서 쓰여지고 있는 파일을 덮어쓰려는 시도도 HDFS에서 실패해야 해요. 소스 파일이 복사되기 전에 (재)이동되면 복사는 FileNotFoundException으로 실패해요. DistCp에서 사용 가능한 모든 옵션은 자세한 Command Line Reference를 참고하세요.

업데이트와 덮어쓰기 (Update and Overwrite)

-update는 대상에 없거나 대상 버전과 다른 소스의 파일을 복사하는 데 사용돼요. -overwrite는 대상에 존재하는 대상 파일을 덮어써요. Update와 Overwrite 옵션은 소스 경로를 다루는 방식이 기본값과 매우 미묘하게 달라서 특별한 주의가 필요해요.

다음 소스 고려:

hdfs://nn1:8020/source/first/1
hdfs://nn1:8020/source/first/2
hdfs://nn1:8020/source/second/10
hdfs://nn1:8020/source/second/20

DistCp가 -update나 -overwrite 없이 호출되면 기본 동작은 /target 아래에 first/와 second/ 디렉터리를 만들 거예요. 따라서:

distcp hdfs://nn1:8020/source/first hdfs://nn1:8020/source/second hdfs://nn2:8020/target

는 /target에 다음 내용을 만들 거예요:

hdfs://nn2:8020/target/first/1
hdfs://nn2:8020/target/first/2
hdfs://nn2:8020/target/second/10
hdfs://nn2:8020/target/second/20

-update 또는 -overwrite 중 하나가 지정되면 소스 디렉터리 자체가 아니라 소스 디렉터리의 내용이 대상으로 복사돼요. 따라서:

distcp -update hdfs://nn1:8020/source/first hdfs://nn1:8020/source/second hdfs://nn2:8020/target

는 /target에 다음 내용을 만들어요:

hdfs://nn2:8020/target/1
hdfs://nn2:8020/target/2
hdfs://nn2:8020/target/10
hdfs://nn2:8020/target/20

확장해서, 두 소스 폴더에 같은 이름의 파일(예: 0)이 있다면 두 소스는 대상의 /target/0에 항목을 매핑할 거예요. DistCp는 이 충돌을 허용하지 않고 중단돼요.

이제 다음 복사 연산을 고려해요:

distcp hdfs://nn1:8020/source/first hdfs://nn1:8020/source/second hdfs://nn2:8020/target

소스/크기:

hdfs://nn1:8020/source/first/1 32
hdfs://nn1:8020/source/first/2 32
hdfs://nn1:8020/source/second/10 64
hdfs://nn1:8020/source/second/20 32

그리고 대상/크기:

hdfs://nn2:8020/target/1 32
hdfs://nn2:8020/target/10 32
hdfs://nn2:8020/target/20 64

결과는:

hdfs://nn2:8020/target/1 32
hdfs://nn2:8020/target/2 32
hdfs://nn2:8020/target/10 64
hdfs://nn2:8020/target/20 32
  • 1은 파일 길이와 내용이 일치하므로 건너뛰어져요.
  • 2는 대상에 없으므로 복사돼요.
  • 10과 20은 내용이 소스와 일치하지 않으므로 덮어써져요.

-update를 사용하면 1은 파일 길이와 내용이 일치하므로 건너뛰어져요. 2는 대상에 없으므로 복사돼요. 10과 20은 내용이 소스와 일치하지 않으므로 덮어써져요. 하지만 -append가 추가로 사용되면 10만 덮어써지고(소스 길이가 대상보다 작음) 20은 (파일이 대상의 원래 길이까지 일치한다면) 파일의 변경분만큼 append돼요. -overwrite를 사용하면 1도 덮어써져요.

동기화 (Sync)

-diff 옵션은 스냅샷 diff로 소스 클러스터에서 대상 클러스터로 파일을 동기화해요. 스냅샷 diff 목록의 파일을 복사하고, 이름을 바꾸고, 제거해요. -diff 옵션을 사용할 때는 -update 옵션을 포함해야 해요. 대부분의 클라우드 제공자는 현재 동기화와 잘 동작하지 않아요.

사용법:

hadoop distcp -update -diff <from_snapshot> <to_snapshot> <source> <destination>

예:

hadoop distcp -update -diff snap1 snap2 /src/ /dst/

위 명령은 /src/의 스냅샷 snap1에서 snap2로의 변경(즉 snap1에서 snap2로의 스냅샷 diff)을 /dst/에 적용해요. 명백히 /src/에 스냅샷 snap1과 snap2가 모두 있어야 해요. 하지만 대상 /dst/에도 <from_snapshot>, 이 경우 snap1과 같은 이름의 스냅샷이 있어야 해요. 대상 /dst/는 snap1 이후 새 파일 연산(create, rename, delete)이 없어야 해요. 이 명령이 끝나면 /dst/에 새 스냅샷 snap2는 생성되지 않는다는 점에 유의하세요. -diff 옵션을 사용하려면 -update가 필요해요.

예를 들어 /src/에서 snap1 생성 후 snap2 생성 전에 1.txt가 추가되고 2.txt가 삭제됐다면, 위 명령은 1.txt를 /src/에서 /dst/로 복사하고 2.txt를 /dst/에서 삭제해요.

실험 1: 인접한 두 스냅샷의 diff 동기화 (Experiment 1: Syncing diff of two adjacent snapshots)

시작 전 준비:

# Create source directory
hdfs dfs -mkdir /src/ /dst/
# Allow snapshot on source
hdfs dfsadmin -allowSnapshot /src/
# Create a snapshot (empty one)
hdfs dfs -createSnapshot /src/ snap1
# Allow snapshot on destination
hdfs dfsadmin -allowSnapshot /dst/
# Create a from_snapshot with the same name
hdfs dfs -createSnapshot /dst/ snap1

# Put one text file under /src/
echo "This is the 1st text file." > 1.txt
hdfs dfs -put 1.txt /src/
# Create the second snapshot
hdfs dfs -createSnapshot /src/ snap2

# Put another text file under /src/
echo "This is the 2nd text file." > 2.txt
hdfs dfs -put 2.txt /src/
# Create the third snapshot
hdfs dfs -createSnapshot /src/ snap3

그런 다음 distcp sync를 실행해요:

hadoop distcp -update -diff snap1 snap2 /src/ /dst/

위 명령은 성공해야 해요. 1.txt는 /src/에서 /dst/로 복사돼요. 다시 한번, -update 옵션이 필요해요. 같은 명령을 다시 실행하면 대상에 snap1 이후 새 파일 1.txt가 추가됐기 때문에 DistCp sync failed 예외가 발생해요. 즉, /dst/에서 1.txt를 수동으로 제거하고 sync를 실행하면 명령이 성공할 거예요.

실험 2: 인접하지 않은 두 스냅샷의 diff 동기화 (Experiment 2: syncing diff of two non-adjacent snapshots)

먼저 실험 1에서 정리를 해요.

hdfs dfs -rm -skipTrash /dst/1.txt

sync 명령을 실행하세요. <to_snapshot>이 실험 1의 snap2에서 snap3으로 바뀌었음을 유의하세요.

hadoop distcp -update -diff snap1 snap3 /src/ /dst/

1.txt와 2.txt 모두 /dst/로 복사돼요.

실험 3: 파일 삭제 연산 동기화 (Experiment 3: syncing file delete operation)

실험 2의 마지막부터 계속:

hdfs dfs -rm -skipTrash /dst/2.txt
# Create snap2 at destination, it contains 1.txt
hdfs dfs -createSnapshot /dst/ snap2

# Delete 1.txt from source
hdfs dfs -rm -skipTrash /src/1.txt
# Create snap4 at source, it only contains 2.txt
hdfs dfs -createSnapshot /src/ snap4

지금 sync 명령을 실행해요:

hadoop distcp -update -diff snap2 snap4 /src/ /dst/

2.txt가 복사되고 1.txt는 /dst/ 아래에서 삭제돼요. /src/와 /dst/ 모두 같은 이름 snap2의 스냅샷이 있지만, 스냅샷은 같은 내용일 필요가 없다는 점에 유의하세요. 즉 /dst/의 snap2에 1.txt가 있어도 내용이 다르다면 1.txt는 여전히 /dst/에서 제거돼요. sync 명령은 삭제될 파일의 내용을 확인하지 않아요. 단순히 <from_snapshot>과 <to_snapshot> 사이의 스냅샷 diff 목록을 따를 뿐이에요. 또한 위 단계에서 /dst/에 snap2를 만들기 전에 /dst/에서 1.txt를 삭제해 /dst/의 snap2에 1.txt가 없게 해도 sync 명령은 여전히 성공해요. 존재하지 않는 1.txt를 /dst/에서 삭제하려 할 때 예외를 던지지 않아요.

raw Namespace 확장 속성 보존 (raw Namespace Extended Attribute Preservation)

이 섹션은 HDFS에만 적용돼요. 대상과 모든 소스 경로 이름이 /.reserved/raw 계층에 있다면 'raw' 네임스페이스 확장 속성이 보존돼요. 'raw' xattr은 암호화 메타데이터 같은 내부 기능에 시스템이 사용하며, /.reserved/raw 계층을 통해 접근할 때만 사용자에게 보여요. raw xattr은 /.reserved/raw 접두사가 제공되는지에만 기반해 보존돼요. -p(preserve, 아래 참고) 플래그는 raw xattr 보존에 영향을 주지 않아요. raw xattr이 보존되지 않게 하려면 소스와 대상 경로 중 어느 것에도 /.reserved/raw 접두사를 사용하지 않으면 돼요. 소스와 대상 경로의 일부에만 /.reserved/raw 접두사가 지정되면 오류가 표시되고 0이 아닌 종료 코드가 반환돼요.

명령줄 옵션 (Command Line Options)

Flag Description Notes
-p[rbugpcaxte] 보존: r: 복제 수, b: 블록 크기, u: 사용자, g: 그룹, p: 권한, c: 체크섬 유형, a: ACL, x: XAttr, t: 타임스탬프, e: erasure coding 정책 -update가 지정되면 파일 크기도 다르지 않는 한(즉 파일이 다시 생성되지 않는 한) 상태 업데이트가 동기화되지 않아요. -pa를 지정하면 ACL은 권한의 상위 집합이므로 DistCp는 권한도 보존해요. -pr 옵션은 소스와 대상 디렉터리가 모두 erasure coded가 아닐 때만 유효해요.
-i 오류 무시 부록에서 설명하듯이, 이 옵션은 기본 경우보다 복사에 대해 더 정확한 통계를 유지해요. 또한 실패한 복사의 로그를 보존하는데, 이것은 디버깅에 가치가 있어요. 마지막으로 실패한 map은 모든 split이 시도되기 전에 작업을 실패시키지 않아요.
-log <logdir> <logdir>에 로그 작성 DistCp는 복사를 시도하는 각 파일의 로그를 map 출력으로 유지해요. map이 실패하면, 재실행되면 로그 출력은 유지되지 않아요.
-v SKIP/COPY 로그에 추가 정보(경로, 크기) 기록 이 옵션은 -log 옵션과만 사용할 수 있어요.
-m <num_maps> 최대 동시 복사 수 데이터를 복사할 map 수를 지정해요. map이 많다고 반드시 처리량이 좋아지지는 않는다는 점에 유의하세요.
-overwrite 대상 덮어쓰기 map이 실패하고 -i가 지정되지 않으면 split의 모든 파일(실패한 파일뿐 아니라)이 다시 복사돼요. Usage 문서에서 논의했듯이 대상 경로 생성에 대한 의미론도 바꾸므로 사용자가 주의해서 사용해야 해요.
-update 소스와 대상이 크기, 블록 크기, 체크섬에서 다르면 덮어쓰기 앞서 언급했듯이 이것은 "sync" 연산이 아니에요. 검사 기준은 소스·대상 파일 크기, 블록 크기, 체크섬이며, 다르면 소스 파일이 대상 파일을 대체해요. Usage 문서에서 논의했듯이 대상 경로 생성에 대한 의미론도 바꾸므로 사용자가 주의해서 사용해야 해요.
-append 대상에 append (소스가 대상보다 길면) 소스 파일이 대상보다 클 때만 append.

DistCp의 아키텍처 (Architecture of DistCp)

새 DistCp의 컴포넌트는 다음 범주로 분류할 수 있어요:

  • DistCp Driver
  • Copy-listing generator
  • Input-formats and Map-Reduce components

DistCp Driver

DistCp Driver 컴포넌트는 다음을 담당해요:

  • 명령줄에서 DistCp 명령에 전달된 인수를 OptionsParser와 DistCpOptionsSwitch를 통해 파싱.
  • 명령 인수를 적절한 DistCpOptions 객체로 조립하고 DistCp를 초기화. 이 인수는 다음을 포함해요: 소스 경로, 대상 위치, 복사 옵션(예: update-copy 여부, overwrite, 어떤 파일 속성을 보존할지 등).
  • 다음을 통해 복사 연산을 조정:
    • 복사할 파일 목록을 만들기 위해 copy-listing-generator 호출.
    • 복사를 수행할 Hadoop Map-Reduce Job 설정·실행.
    • 옵션에 따라 Hadoop MR Job의 핸들을 즉시 반환하거나 완료까지 대기.

파서 요소는 명령줄에서만(또는 DistCp::run()이 호출될 때) 사용돼요. DistCp 클래스는 DistCpOptions 객체를 구성하고 DistCp 객체를 적절히 초기화해 프로그래밍 방식으로도 사용할 수 있어요.

Copy-listing Generator

copy-listing-generator 클래스는 소스에서 복사할 파일/디렉터리 목록을 만드는 역할을 해요. 소스 경로의 내용(파일/디렉터리, 와일드카드 포함)을 조사하고 복사가 필요한 모든 경로를 SequenceFile에 기록해 DistCp Hadoop Job이 소비하게 해요. 이 모듈의 주요 클래스:

  • CopyListing: 어떤 copy-listing-generator 구현이든 구현해야 하는 인터페이스. 또한 구체적인 CopyListing 구현이 선택되는 팩토리 메서드를 제공해요.
  • SimpleCopyListing: 여러 소스 경로(파일/디렉터리)를 받아들이고 각각 아래의 모든 개별 파일과 디렉터리를 복사용으로 재귀적으로 나열하는 CopyListing의 구현.
  • GlobbedCopyListing: 소스 경로의 와일드카드를 확장하는 또 다른 CopyListing 구현.

InputFormats와 MapReduce 컴포넌트 (InputFormats and MapReduce Components)

복사가 파티셔닝되는 방식을 결정하는 InputFormats와 map implementer.

부록 (Appendix)

Map 크기 조정 (Map sizing)

기본적으로 DistCp는 각 map이 대략 같은 바이트 수를 복사하도록 각 map의 크기를 비슷하게 조정하려 시도해요. 파일이 가장 미세한 세분화 단위이므로 동시 복사기(map) 수를 늘린다고 항상 동시 복사 수나 전체 처리량이 늘어나지는 않는다는 점에 유의하세요. 새 DistCp는 또한 map을 "동적으로" 크기 조정하는 전략을 제공해 더 빠른 data-node가 느린 노드보다 더 많은 바이트를 복사할 수 있게 해줘요. -strategy dynamic(Architecture에서 설명)을 사용하면 각 map-task에 고정된 소스 파일 집합을 할당하는 대신, 파일을 여러 집합으로 쪼개요. 집합 수는 보통 2-3배의 계수만큼 map 수를 초과해요. 각 map은 chunk에 나열된 모든 파일을 집어 복사해요. chunk가 소진되면 새 chunk를 획득해 처리하며, 마지막 chunk까지 계속해요. 소스 경로를 고정된 map에 할당하지 않음으로써, 더 빠른 map-task(즉 data-node)가 더 많은 chunk를 소비해 느린 노드보다 더 많은 데이터를 복사할 수 있어요. 이 분배는 균일하지 않지만 각 mapper의 용량에 관해 공정해요. 동적 전략은 DynamicInputFormat으로 구현돼요. 대부분의 조건에서 우수한 성능을 제공해요. map 수를 소스·대상 클러스터의 크기, 복사 크기, 사용 가능한 대역폭에 맞게 조정하는 것은 장기 실행 및 정기 실행 작업에 권장돼요.

HDFS 버전 간 복사 (Copying Between Versions of HDFS)

서로 다른 주요 버전의 Hadoop(예: 1.X와 2.X) 간 복사에는 보통 WebHdfsFileSystem을 사용해요. 이전 HftpFileSystem과 달리 webhdfs는 읽기·쓰기 연산 모두에 사용 가능하므로 DistCp를 소스와 대상 클러스터 모두에서 실행할 수 있어요. 원격 클러스터는 webhdfs://<namenode_hostname>:<http_port>로 지정돼요. 같은 주요 버전의 Hadoop 클러스터(예: 2.X와 2.X) 간 복사에는 더 나은 성능을 위해 hdfs 프로토콜을 사용해요.

Wire를 통한 보안 복사 (Secure Copy over the wire with distcp)

distcp와 함께 "swebhdfs://" 스킴을 사용해 wire 상에서 보안 복사를 수행할 수 있어요.

객체 스토어에서의 DistCp (DistCp on object stores)

객체 스토어 내에서 복사:

hadoop distcp wasb://[email protected]/current \
  wasb://[email protected]/old

-update를 사용해 변경된 파일만 복사:

hadoop distcp -update -numListstatusThreads 20  \
  s3a://history/2016 \
  hdfs://nn1:8020/history/2016

객체 스토어는 파일 나열이 느리므로, 큰 디렉터리 트리에서 -update 연산을 수행할 때는 -numListstatusThreads 옵션을 설정하는 것을 고려해요 (제한은 40 스레드). DistCp -update가 객체 스토어와 함께 사용될 때는 일반적으로 두 스토어 간 체크섬 알고리즘이 다르다면 체크섬이 아니라 개별 파일의 수정 시간과 길이만 비교해요. 체크섬 알고리즘이 서로 다른 두 객체 스토어 간 distcp -update는 파일 복사를 건너뛸지 결정하기 위해 소스와 대상 파일의 수정 시간을 파일 크기와 함께 비교해요. 이 동작은 distcp.update.modification.time 속성으로 제어되며 기본적으로 true로 설정돼요. 소스 파일이 대상 파일보다 더 최근에 수정됐다면 내용이 변경된 것으로 가정하고 파일을 업데이트해야 해요. 머신 간 clock skew가 없음을 보장해야 해요. 대부분의 객체 스토어가 디렉터리에 유효한 타임스탬프를 가진다는 사실은 무관해요. 파일 타임스탬프만 비교돼요. 하지만 클라이언트 컴퓨터의 시계가 인프라와 가까워서 타임스탬프가 클라이언트/HDFS 클러스터와 객체 스토어 사이에서 일관되게 유지되는 것이 중요해요. 그렇지 않으면 변경된 파일이 놓치거나 너무 자주 복사될 수 있어요. distcp.update.modification.time은 두 스토어 중 하나가 체크섬 검증이 없어 둘 사이에 호환 불가능한 체크섬 비교가 발생할 때만 사용돼요. 속성이 true로 설정돼 있어도 두 스토어 사이에 유효한 체크섬 비교가 있다면 사용되지 않아요. 수정 시간 검사를 끄려면 core-site.xml에 설정해요:

<property>
        <name>distcp.update.modification.time</name>
        <value>false</value>
</property>

객체 스토어에서의 DistCp 참고 사항:

  • -atomic 옵션은 임시 데이터의 rename을 유발하므로 연산 마지막에 작업을 커밋하는 시간이 크게 늘어나요. 또한 (선택적으로 wasb://를 제외한) 객체 스토어는 디렉터리의 원자적 rename을 제공하지 않으므로 -atomic 연산은 약속한 것을 실제로 전달하지 않아요. 사용을 피하세요.

  • -append 옵션은 지원되지 않아요.

  • -diff와 rdiff 옵션은 지원되지 않아요.

  • -skipCrc 플래그 값과 무관하게 CRC 검사는 수행되지 않아요.

  • 권한, 사용자·그룹 정보, 속성 체크섬, 복제 보존을 포함한 모든 -p 옵션은 일반적으로 무시돼요. wasb:// 커넥터는 정보를 보존하지만 권한은 강제하지 않아요.

  • 일부 객체 스토어 커넥터는 출력의 인메모리 버퍼링 옵션을 제공해요 — 예를 들어 S3A 커넥터예요. 큰 파일을 복사하는 동안 그런 옵션을 사용하면 힙 오버플로우나 YARN 컨테이너 종료 같은 어떤 형태의 out of memory 이벤트가 트리거될 수 있어요. 이것은 클러스터와 객체 스토어 사이의 네트워크 대역폭이 제한될 때(원격 객체 스토어 작업 시에 흔함) 특히 흔해요. 그런 옵션을 비활성화/회피하고 디스크 버퍼링에 의존하는 것이 가장 좋아요.

  • 단일 객체 스토어 내의 복사 연산도 객체 스토어가 내부적으로 더 효율적인 COPY 연산을 구현해도 Hadoop 클러스터에서 여전히 발생해요. 즉, 다음과 같은 연산은

    hadoop distcp s3a://bucket/datasets/set1 s3a://bucket/datasets/set2
    

    각 바이트를 Hadoop 워커 노드로 내려갔다가 bucket으로 다시 올려요. 느릴 뿐만 아니라 비용이 발생할 수 있음을 의미해요. -direct 옵션을 사용해 객체 스토어 대상 경로에 직접 쓸 수 있으며, 그렇지 않으면 발생하는 잠재적으로 매우 비싼 임시 파일 rename 연산을 피할 수 있어요.

자주 묻는 질문 (Frequently Asked Questions)

왜 -update가 기존 대상 디렉터리 아래에 소스 상위 디렉터리를 만들지 않나요?

-update와 -overwrite의 동작은 이 문서의 Usage 섹션에 자세히 설명돼 있어요. 간단히 말해서, 옵션 중 하나가 기존 대상 디렉터리와 함께 사용되면 각 소스 디렉터리의 내용이 소스 디렉터리 자체보다는 덮어써져 복사돼요. 이 동작은 레거시 DistCp 구현과도 일치해요.

새 DistCp는 레거시 DistCp와 의미론이 어떻게 다르나요?

  • 복사 중 건너뛴 파일은 레거시 DistCp로 복사할 때 파일 속성(권한, 소유자/그룹 정보 등)도 변경되지 않았어요. 이제 이들은 파일 복사가 건너뛰어져도 업데이트돼요.
  • 레거시 DistCp에서는 소스 경로 입력 중 빈 루트 디렉터리가 대상에 만들어지지 않았어요. 이제 만들어져요.

새 DistCp가 레거시보다 더 많은 map을 사용하는 이유는?

레거시 DistCp는 복사-작업이 실행되기 전에 실제로 대상에 복사해야 하는 파일을 알아낸 다음, 복사에 필요한 만큼의 map을 실행해요. 따라서 파일의 대부분을 건너뛰어야 한다면(예를 들어 이미 존재하므로) 더 적은 map이 필요해요. 결과적으로 설정(즉 M/R 작업 전)에 소요되는 시간은 더 높아요. 새 DistCp는 소스 경로의 내용만 계산해요. 건너뛸 수 있는 파일을 걸러내려고 시도하지 않아요. 그 결정은 M/R 작업 실행 때까지 미뤄져요. 이것은 (실행 시간 측면에서) 훨씬 빠르지만, 실행되는 map 수는 -m 옵션에 지정된 수 또는 지정되지 않으면 20(기본값)이 돼요.

더 많은 map이 지정되면 DistCp가 더 빨라지지 않는 이유는?

현재 DistCp의 가장 작은 작업 단위는 파일이에요. 즉, 파일은 하나의 map에 의해서만 처리돼요. map 수를 파일 수를 초과하는 값으로 늘려도 성능 이점은 없어요. 실행되는 map 수는 파일 수와 같아질 거예요.

DistCp가 메모리를 모두 소진하는 이유는?

-m 옵션으로 지정된 수의 map이 한 번에 실행된다면, 각 map은 한 번에 하나의 소스 파일을 읽어요. -m이 높게 설정되면 많은 수의 작은 파일이 병렬로 읽히며, 각 파일이 메모리에 로드될 수 pd지 메모리 부족이 발생할 수 있어요. 일반적으로 작은 파일이 많은 복사에서는 map 수를 줄이는 것이 좋아요.

예:

bash$ hadoop distcp /source /target

더 알아보기 (Learn more)