본문 바로가기
카테고리 없음

[HDFS] TestDFSIO - 하둡 클러스터 성능 측정 도구(Hadoop Cluster Benchmark Tool)

by 왕 달팽이 2019. 4. 6.
반응형

하둡 클러스터를 구축하고 성능을 측정하고 싶은 경우가 있다. 내가 구축한 클러스터가 어느정도의 성능을 가지고 있는지, 기준치에 못 미치는 성능을 보인다면 얼마나 더 많은 노드를 추가해야하는지 가늠하기 위해서 클러스터의 객관적인 성능 측정 도구가 필요하다.

 

빅데이터 플랫폼 하둡

 

하둡에서는 여러 성능 측정 도구를 제공하고 있다. 그 중에 클러스터의 성능을 I/O(입출력)의 측면에서 분석할 수 있는 'TestDFSIO'라는 벤치마크 도구가 있다.

TestDFSIO

하둡 릴리즈에서 hadoop-mapreduce-client-jobclient-{버전}-tests.jar 파일에 패키징되어 있는 TestDFSIO는 클러스터의 입출력 성능을 측정할 수 있는 도구다. 하둡 소스코드처럼 TestDFSIO 소스코드도 깃허브(github)에 오픈소스로 공개되어 있다. (링크 : 깃허브 소스코드)

소스코드를 열어보면 알겠지만 TestDFSIO는 MapReduce 잡을 통해 입출력 성능을 측정한다. (버전에 따라 버그가 있을 수도 있으니 문제가 생기면 소스코드를 열어서 버그와 관련된 부분을 확인해보도록 하자)

 

입출력 성능 측정을 수행하는 MapReduce 잡의 맵 태스크의 개수는 만들어질 파일의 개수(-nrFiles 옵션)와 동일하며, 리듀서 개수는 하나로 고정이다.

TestDFSIO 사용방법

TestDFSIO는 yarn 명령을 이용해서 실행할 수 있다.

$ yarn jar {jar 파일 경로} TestDFSIO {옵션들..}

파일 사이즈, 파일 개수와 관련된 옵션은 다음과 같다.

옵션 설명
-nrFiles 입출력 테스트에서 클러스터에 생성할 파일의 개수. 맵 리듀스 작업의 맵 태스크 개수.
-size 생성되는 파일 하나당 크기
-bufferSize 입출력 테스트에 사용될 버퍼 사이즈
-resFile 테스트 결과를 저장할 파일

-nrFiles는 입출력 테스트에서 클러스터에 만들 파일의 개수를 의미한다. 입출력 테스트를 수행하는 맵 리듀스 작업에서 매퍼(Mapper) 하나당 하나의 파일을 생성하기 때문에 -nrFiles로 명시한 숫자는 결국 맵 태스크 개수를 의미하게 된다.

 

-size 혹은 -fileSize는 생성되는 파일 하나당 크기를 의미한다. 따라서 클러스터에는 (-nrFiles) * (-size) 만큼의 데이터가 생성된다.

 

정확한 테스트를 위해서 -nrFiles와 -size를 적절한 값으로 설정할 필요가 있다. 일반적으로 -nrFiles 값은 클러스터에서 사용할 수 있는 vcores 개수보다 적은 값을 설정하는게 좋다. -nrFiles 값이 vcores 값보다 크게 되면 두 회 이상의 맵 태스크 사이클이 돌게 된다. 이 때, 마지막 맵 태스크 사이클에서 동작하는 입출력은 이전 사이클과 비교하여 입출력 간섭을 덜 받게 된다. 결국 마지막 사이클의 성능이 좀 더 좋게 나올 가능성이 있다. 결국 마지막 사이클에서 수행된 데이터가 전체 데이터에 영향을 주게 될 가능성이 있다. (결국 표준 편차가 높아져서 테스트 결과의 신뢰성에 악영향을 줄 수 있다.)

 

-size 값은 테스트가 10분 이상 지속될 수 있도록 충분히 큰 값으로 지정하는 것이 좋다.

여기에 추가로 입출력 연산 옵션도 함께 명시해야 한다.

옵션 설명
-read 파일의 앞쪽에서 시작하여 파일의 끝까지 버퍼 사이즈 단위로 읽기 연산을 수행한다. 
-read -random 파일의 랜덤 오프셋(Offset)에서 버퍼 사이즈만큼 읽어 들인다. 읽은 데이터의 양이 파일 사이즈만큼 될때까지 반복한다.
-read -backward 파일의 뒷쪽부터 시작하여 파일의 앞쪽까지 버퍼 사이즈 단위로 읽기 연산을 수행한다.
-read -skip {SKIP SIZE} 파일을 띄엄띄엄 읽는다. 버퍼사이즈만큼 읽고, SKIP SIZE 만큼 건너뛴 다음 다시 버퍼 사이즈만큼 읽기를 반복한다.
-write 파일을 쓴다. 
-append 파일에 데이터를 append한다. FilesSystem.append() 연산을 이용한다. 
-trucate 파일을 특정 사이즈로 자른다.
-clean 테스트에 사용된 파일과 디렉토리를 정리한다. 

read 테스트는 write 테스트를 이용하여 파일이 만들어진 이후 수행해야한다.

부가적인 설정들 (문제 해결)

기본적인 테스트는 위에 쓴 내용들로 가능하지만 클러스터 설정에 따라서 추가로 설정을 해야하는 경우가 있다. 테스트를 진행하면서 만난 에러와 해결방법을 정리해보겠다.

 

1. 테스크 디렉토리 변경

TestDFSIO를 수행할 때 별도로 테스트 경로를 명시하지 않으면 루트(‘/‘) 디렉토리에 테스트 디렉토리들을 만들고 파일 입출력을 진행한다.

HDFS 파일 시스템은 다른 유닉스 파일 시스템처럼 디렉토리, 파일에 대한 권한 설정을 하게 되는데, 일반적으로 루트 디렉토리에 대해서 일반 유저에 권한을 열어주지 않는다. 루트 디렉토리에 디렉토리 생성 권한이 없는 경우 권한과 관련된 에러가 발생하여 테스트 진행이 되지 않는다.

java.io.IOException: Permission denied: user={계정 이름}, access=WRITE, inode="/" {권한 내용}
at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.check(FSPermissionChecker.java:307)
at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:214)
at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:190)
at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPermission(FSDirectory.java:1752)
at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPermission(FSDirectory.java:1736)
at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkAncestorAccess(FSDirectory.java:1719)
...

이 경우 테스트 디렉토리를 생성할 경로를 권한이 있는 경로로 설정해줘야 한다.

$ -Dtest.build.data=/path/test_dir

test.build.data 옵션으로 명시한 hdfs 경로에 디렉토리가 만들어지고 파일 입출력 테스트가 정상적으로 동작하게 된다.

 

2. 맵리듀스 작업 큐(MapReduce Job Queue) 변경

앞서 말했듯이 TestDFSIO는 MapReduce 작업을 이용해서 입출력 테스트를 진행한다. 맵 리듀스 작업은 특정 작업 큐에 Submit 되는데, TestDFSIO는 기본적으로 ‘default’ 큐에 작업을 Submit 한다. 문제는 구축해놓은 Yarn 클러스터에 default 큐가 없는 경우 혹은 default 큐에서 사용할 수 있는 컨테이너의 숫자가 작은 경우다.

 

다음은 default 큐를 제거한 클러스터에서 테스트를 진행했을 때 만난 예외다.

java.io.IOException: org.apache.hadoop.yarn.exceptions.YarnException: Failed to submit application_1234567890123_0100 to YARN : Application application_1234567890123_0100 submitted by user {user 이름} to unknown queue: default
at org.apache.hadoop.mapred.YARNRunner.submitJob(YARNRunner.java:316)
at org.apache.hadoop.mapreduce.JobSubmitter.submitJobInternal(JobSubmitter.java:240)
at org.apache.hadoop.mapreduce.Job$10.run(Job.java:1290)
at org.apache.hadoop.mapreduce.Job$10.run(Job.java:1287)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:415)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1762)
at org.apache.hadoop.mapreduce.Job.submit(Job.java:1287)
at org.apache.hadoop.mapred.JobClient$1.run(JobClient.java:575)
at org.apache.hadoop.mapred.JobClient$1.run(JobClient.java:570)
at java.security.AccessController.doPrivileged(Native Method)
...

이 경우 테스트를 위한 맵 리듀스 작업을 별도의 큐에 Submit 해야 한다.

-Dmapred.job.queue.name=queueName

클러스터의 리소스 매니저(Resource Manager)에서 TestDFSIO 작업이 어떤 큐로 Submit 되었는지 모니터링 할 수 있다.

 

3. 리듀서(Reducer) 출력파일 압축 여부

TestDFSIO 작업의 리듀서가 만들어 내는 파일의 이름은 part-00000 이다. 만약 하둡 클러스터의 설정때문에 part-00000.gz 파일로 출력이 만들어 질 수 있다. 이 경우 리듀스 파일을 다시 읽어 들일 때, part-00000 파일을 찾지 못해서 에러가 발생한다.

java.io.FileNotFoundException: File does not exist: {test_path}/io_write/part-00000
at org.apache.hadoop.hdfs.server.namenode.INodeFile.valueOf(INodeFile.java:71)
at org.apache.hadoop.hdfs.server.namenode.INodeFile.valueOf(INodeFile.java:61)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getBlockLocationsInt(FSNamesystem.java:1847)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getBlockLocations(FSNamesystem.java:1819)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getBlockLocations(FSNamesystem.java:1733)
at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.getBlockLocations(NameNodeRpcServer.java:588)
at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.getBlockLocations(ClientNamenodeProtocolServerSideTranslatorPB.java:366)
at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java)
at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:616)
at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:982)
at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2217)
at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2213)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:422)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1762)
at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2211)

이 문제를 해결하기 위해 압축 설정을 끄도록 옵션을 명시했다. 어짜피 입출력 성능을 볼 것이기 때문에 중간에 CPU 작업이 들어가지 않는다고 큰 문제는 없을 것이라는 판단에 의해서였다.

-Dmapreduce.output.fileoutputformat.compress=false

이 옵션으로 맵리듀스의 출력 리듀스 파일을 압축하지 않게 되고, 정상적으로 part-0000 파일을 만들어 정상적으로 테스트가 진행된다.

테스트 결과 분석

테스트를 수행하면 다음과 같은 결과를 얻을 수 있다.

19/04/03 21:19:38 INFO fs.TestDFSIO: ----- TestDFSIO ----- : write  
19/04/03 21:19:38 INFO fs.TestDFSIO: Date & time: Wed Apr 03 21:19:38 KST 2019  
19/04/03 21:19:38 INFO fs.TestDFSIO: Number of files: 1024  
19/04/03 21:19:38 INFO fs.TestDFSIO: Total MBytes processed: 1048576  
19/04/03 21:19:38 INFO fs.TestDFSIO: Throughput mb/sec: 46.56  
19/04/03 21:19:38 INFO fs.TestDFSIO: Average IO rate mb/sec: 44.26  
19/04/03 21:19:38 INFO fs.TestDFSIO: IO rate std deviation: 8.14  
19/04/03 21:19:38 INFO fs.TestDFSIO: Test exec time sec: 44.74  
19/04/03 21:19:38 INFO fs.TestDFSIO:

이 로그 위쪽으로 남는 내용은 입출력 맵 리듀스 작업에 대한 카운터(Counter) 정보이고, 입출력 테스트의 최종 결과는 마지막에 위 텍스트처럼 남는다.

 

항목 설명
Date & time 테스트의 종료 시간에 대한 정보
Number of Files  맵 리듀스 작업에서 생성된 파일의 개수 (-nrFiles 옵션)
Total MBytes processed 맵 리듀스 작업에서 처리한 데이터의 양. ((-nrFiles) * (-size)) 값
Throughput mb/sec Total MBytes processed’ 항목을 ‘Number of Files’를 처리하는데 소요된 시간의 합으로 나눈 값. 
즉, 100MB 파일 10개를 쓰는데, 파일당 10초가 걸렸다면, ((100MB * 10) / (10 * 10))이 이 항목 값.
Average IO rate mb/sec 각 파일의 처리 속도 평균
IO rate std deviation  IO rate 항목의 표준편차. 이 값이 높으면 파일마다 처리 속도가 들쑥날쑥했다는 의미로 받아들이면 됨.
Test exec time sec 맵 리듀스 작업의 수행 시간

 

이 결과를 비교해가며 테스트를 진행하면 된다.

반응형

댓글