본문 바로가기
Old Posts/Hadoop

[Hadoop] TestDFSIO - 하둡 클러스터 성능 측정 도구 사용법 및 예제

by A6K 2021. 8. 8.

구축한 하둡 클러스터의 입출력 성능을 측정하고 싶은 경우가 있다. 새로 구매한 서버들을 이용해서 클러스터를 구축했을 때 성능이 어느정도까지 뽑히는지 체크하거나 일정 수준 이상의 입출력 성능을 제공하기 위해서 어느정도의 장비를 투입해야하는지 가늠하기 위함이다.

하둡은 여러가지 클러스터 성능 측정 도구를 제공하고 있다. 그 중에 클러스터의 입출력 속도 측정을 위한 'TestDFSIO'라는 벤치마크 도구에 대한 사용법과 예제를 정리해보겠다.

TestDFSIO란?

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

TestDFSIO는 맵-리듀스(MapReduce) 작업을 통해 입출력 성능을 측정한다. 성능 측정을 위한 맵 태스크의 개수는 만들어질 파일의 개수와 동일하며 리듀서는 하나로 고정된다. 만들어질 파일 개수는 -nrFiles 옵션으로 넘겨줄 수 있다.

TestDFSIO 사용법

TestDFSIO는 Yarn 명령을 통해 사용할 수 있다.

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

TestDFSIO에서 사용할 수 있는 파일 사이즈와 파일 개수에 관한 옵션은 다음과 같다.

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

-nrFiles : 입출력 테스트에서 클러스터에 만들 파일의 개수를 입력할 수 있는 옵션이다. 입출력 테스트를 수행하는 맵-리듀스 작업에서 매퍼(Mapper) 하나당 하나의 파일을 생성한다. 따라서 -nrFiles로 넘겨준 숫자는 결국 실행할 맵-리듀스 작업의 맵 태스크 개수를 결정하게 된다.

-size (-fileSize) : 생성되는 파일 하나당 크기를 지정한다. 결국 클러스터 전체로 보면( -nrFiles) * ( -size ) 만큼의 데이터가 생성된다고 보면 된다.

정확한 테스트를 위해서 -nrFiles와 -size를 적당한 값으로 설정해야한다. 적당한 값이라는게 제일 어렵긴한데 일반적으로 -nrFiles 값은 클러스터에서 사용할 수 있는 vcores 개수보다 적은 값을 설정하는게 좋다고 한다. -nrFiles 값이 vcores 값보다 크게 되면 매퍼의 실행 사이클이 2회 이상돌게 된다. 이 경우 마지막 맵 태스크 아시클에서 동작하는 입출력 작업은 이전 사이클과 비교해서 입출력 간섭을 덜 받게 된다. 따라서 마지막 사이클에서 수행한 테스트 결과가 전체 성능에 좋은 영향을 미치게되어 성능이 좀 더 잘 나올 가능성이 있다. -size 값은 테스트가 10분 이상 지속될 수 있도록 충분히 큰 값으로 지정하는 것이 좋다.

TestDFSIO에서 사용할 수 있는 입출력 연산은 다음과 같다.

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

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


TestDFSIO 관련 기타 고려사항

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

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)
...

이 경우 테스트 디렉토리를 루트가 아니라 TestDFSIO 툴을 실행할 계정이 권한을 가지고 있는 디렉토리로 변경해줘야한다. -Dtest.build.data 옵션을 추가해서 테스트 디렉토리를 변경할 수 있다.

$ yarn jar {jar 파일 경로} -Dtest.build.data=/path/test_dir TestDFSIO {옵션들..}

2. 맵-리듀스 작업큐 변경

TestDFSIO 작업은 맵-리듀스 작업으로 실행된다. 따라서 Yarn 클러스터에 TestDFSIO 작업이 제출(submit)된다. Yarn 클러스터는 사용자가 제출한 작업을 특정 큐를 통해 받는데, TestDFSIO 작업은 기본적으로 'default' 큐에 제출된다. 문제는 구축해놓은 Yarn 클러스터의 default 큐가 없거나 default 큐에서 가용한 컨테이너의 숫자가 매우 작은 경우다. 서비스용으로 Yarn 클러스터를 구축한 경우 default 큐를 제거하거나 매우 작게 설정해놓는 경우가 많다.

default 큐를 제거한 클러스터에 TestDFSIO 툴을 실행하면 다음 에러를 만나게 된다.

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)
...

이 경우 맵-리듀스 작업을 별도의 큐에 제출해야한다.

$ yarn jar {jar 파일 경로} -Dmapred.job.queue.name=queueName TestDFSIO {옵션들..}

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

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 작업이 들어가지 않는다고 큰 문제는 없을 것이라는 판단에 의해서였다.

$ yarn jar {jar 파일 경로} -Dmapreduce.output.fileoutputformat.compress=false TestDFSIO {옵션들..}

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


TestDFSIO 테스트 결과 분석

TestDFSIO 작업이 모두 끝나면 다음 결과를 얻을 수 있다.

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) 정보가 남고, 입출력 테스트에 대한 최종 결과는 마지막에 위 텍스트처럼 남게된다.

TestDFSIO의 결과로 나오는 항목은 다음과 같다.

결과 항목 설명
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 맵 리듀스 작업의 수행 시간

 

댓글