맵리듀스퍼포먼스튜닝하기 2012.11 정재화 이저작물은크리에이티브커먼즈코리아저작자표시 - 비영리 - 변경금지 2.0 대한민국라이선스에따라이용하실수있습니다.
About me jhjung@gruter.com 현 ) 그루터 (www.gruter.com) 책임개발자 전 ) 큐릭스, NHN, 엔씨소프트 www.blrunner.com www.twitter.com/blrunner78 저서 ) 시작하세요! 하둡프로그래밍 : 기초부터실무까지하둡의모든것 ( 위키북스, 2012 년 10 월출간 ) 2
Index 1. 셔플튜닝하기 1.1 셔플이란? 1.2 셔플환경변수튜닝 1.3 콤바이너클래스적용 1.4 맵출력데이터압축 2. DFS 블록사이즈수정 3. JVM 재사용 4. 투기적인잡실행 5. DBMS에데이터입력하기 3
1.1 셔플이란 셔플은메모리에저장돼있는매퍼의출력데이터를파티셔닝과정렬을해서로컬디스크에저장한후, 네트워크를통해리듀서의입력데이터로전달되는과정을의미합니다 1. 스플릿생성 2. 맵 3. 스필 4. 병합 5. 복사 6. 정렬 7. 리듀스 입력스플릿 맵 1 리듀스 1 입력스플릿 맵 2 리듀스 n 입력스플릿 맵 n 메모리버퍼파티션맵출력데이터 메모리버퍼, 파일 파일 4
1.1 셔플이란 속성내용기본값 io.sort.mb 맵의출력데이터를저장할버퍼의크기 100mb io.sort.spill.percent io.sort.factor tasktracker.http.threads mapred.reduce.parallel.copies 맵의출력데이터를저장하는버퍼가일정한비율에도달하면로컬디스크로스필을실행함 하나의정렬된출력파일로병합하기위한스필파일의개수 맵의출력데이터를리듀스태스크에게제공하기위한태스크트래커의워커쓰레드개수. 전체클러스터에적용되며, 잡별로다르게설정할수는없음 맵의출력데이터를리듀스태스크로복사하기위한쓰레드개수 0.80 à 80% 10 40 5 5
1.1 셔플이란 속성내용기본값 mapred.job.shuffle.input.buffe r.percent mapred.job.shuffle.merge.per cent mapred.inmem.merge.thresho ld 셔플된맵의출력데이터는리듀스태스크트래커의메모리버퍼로복사됨. 이때메모리버퍼로사용할리듀스태스크트래커의힙메모리사이즈비율을설정함 리듀스태스크의메모리버퍼에저장된맵의출력데이터를스필하기위한임계치 리듀스태스크의메모리버퍼에서처리할파일개수가일정개수에도달해도스필을실행함. 0.70 à 70% 0.66 à 80% 1000 6
1.2 셔플환경변수튜닝 맵태스크는스필파일의개수를줄이는것이유리함 튜닝대상맵리듀스잡 튜닝속성 입력데이터크기 : 11G 작업유형 : Customer CompositeKey 와 GroupKey 를이용한보조정렬 작업수행시간 : 약 13 분소요 io.sort.mb: 100mb à 200mb io.sort.factor: 10 à 30 맵리듀스잡실행 전체클러스터의환경설정값을수정하지않고, 개별적인잡의설정값만변경함 런타임에서 D 옵션을이용해환경변수값을수정함./bin/hadoop jar wikibooks-hadoop-examples.jar wikibooks.hadoop.chapter06.delaycountwithdatekey -D io.sort.mb=200 -D io.sort.factor=30 input delay_count_sort2 7
1.2 셔플환경변수튜닝 맵리듀스잡실행시 Java heap space 오류발생 12/08/27 00:51:45 INFO mapred.jobclient: Task Id : attempt_201208250324_0040_m_000000_0, Status : FAILED Error: Java heap space 12/08/27 00:51:45 INFO mapred.jobclient: Task Id : attempt_201208250324_0040_m_000001_0, Status : FAILED Error: Java heap space 12/08/27 00:51:47 INFO mapred.jobclient: Task Id : attempt_201208250324_0040_m_000002_0, Status : FAILED Error: Java heap space 태스크트래커에서실행하는 JVM 의기본힙메모리크기 (mapred.child.java.opts) 를초과했기때문에오류가발생함 mapred.child.java.opts 를 300mb 이상으로설정해서맵리듀스잡을실행해야함 mapred.child.java.opts 를 512mb 로수정해서재실행./bin/hadoop jar wikibooks-hadoop-examples.jar wikibooks.hadoop.chapter06.delaycountwithdatekey -D io.sort.mb=200 -D mapred.child.java.opts=-xmx512m -D io.sort.factor=30 input delay_count_sort3 8
1.2 셔플환경변수튜닝 작업시간 : 12 분 42 초 à 9 분 50 초 튜닝결과비교 카운터 io.sort.* 적용전 io.sort.* 적용후 SLOTS_MILLIS_MAPS 2,395,970 2136,569 SLOTS_MILLIS_REDUCES 717,843 550,099 FILE_BYTES_READ 5,542,981,602 3,933,998,336 HDFS_BYTES_READ 11,966,801,064 11,966,801,064 FILE_BYTES_WRITTEN 7,690,995,377 6,082,012,298 HDFS_BYTES_WRITTEN 7,269 7,269 Reduce shuffle bytes 2,143,640,736 2,138,251,210 Spilled Records 384,330,903 303,881,809 CPU time spent (ms) 2,097,910 1,721,660 Total committed heap usage (bytes) 38,668,533,760 84,327,792,640 Physical memory (bytes) snapshot 43,280,994,304 82,583,814,144 Virtual memory (bytes) snapshot 105,656,713,216 168,085,508,096 셔플파라미터는맵리듀스프로그램코드상에서정렬을사용하는경우에튜닝효과가나타나며, 정렬을사용하지않는잡의셔플파라미터를수정하면기본값을사용하는경우보다성능이나빠지게됨 9
1.3 콤바이너클래스적용 콤바이너클래스는맵의출력데이터가네트워크를통해리듀서로전달되기전에매퍼의출력데이터의크기를줄이는기능을수행함 콤바이너적용전 콤바이너적용후 10 그림출처 : http://hpc.admin-magazine.com/articles/mapreduce-and-hadoop
1.3 콤바이너클래스적용 Job 인터페이스의 setcombinerclass 메소드를호출해서적용. 반드시리듀서클래스를파라미터로설정해야함 job.setcombinerclass(delaycountreducer.class); 튜닝대상맵리듀스잡 입력데이터크기 : 11G 작업유형 : 단순계산 (wordcount 성 ) 튜닝전보다약 40 초가량수행시간단축 콤바이너클래스적용결과비교 카운터콤바이너적용전콤바이너적용후 FILE_BYTES_READ 1,453,088,421 16,577 HDFS_BYTES_READ 11,966,801,064 11,966,801,064 FILE_BYTES_WRITTEN 2,219,075,754 411,2660 HDFS_BYTES_WRITTEN 3,635 3,635 Reduce shuffle bytes 761,365,791 8,760 Spilled Records 167,244,625 1,685 CPU time spent (ms) 1,013,810 930,160 Total committed heap usage 3,8565,642,240 38,504,628,224 Reduce input records 57,482,463 578 Physical memory (bytes) snapshot 42,829,991,936 42,876,624,896 11
1.4 맵출력데이터압축 맵출력데이터를압축하면, 파일 I/O 와네트워크비용이감소함 하둡클러스터에서맵출력데이터를압축하기위해서는, mapred-site.xml 에다음과같이정의함 <!-- 맵출력데이터압축사용여부 --> <property> <name>mapred.compress.map.output</name> <value>true </value> </property> <!-- 클러스터에서사용할압축라이브러리정의 --> <property> <name>io.compression.codecs</name> <value> org.apache.hadoop.io.compress.gzipcodec, org.apache.hadoop.io.compress.defaultcodec, org.apache.hadoop.io.compress.bzip2codec, org.apache.hadoop.io.compress.snappycodec </value> </property> 12
1.4 맵출력데이터압축 스내피 (Snappy) 란구글에서개발한압축라이브러리이며, 하둡 1.02 와 0.23 버전부터정식으로스내피를지원함 압축률을최대한높이기보다는, 적당한압축률로빠르게압축을수행하는것을목표로함 초당 250MB 로압축을수행함 구글내부에서는빅테이블, 구글파일시스템, RPC 시스템등에광범위하게적용됨 공식사이트 : http://code.google.com/p/snappy/ 설치방법 : http://www.blrunner.com/8 13
1.4 맵출력데이터압축 개별적인맵리듀스잡에서맵출력의압축은다음과같이코드를작성함 Gzip job.setoutputformatclass(sequencefileoutputformat.class); SequenceFileOutputFormat.setCompressOutput(job, true); SequenceFileOutputFormat.setOutputCompressorClass(job, GzipCodec.class); SequenceFileOutputFormat.setOutputCompressionType(job, CompressionType.BLOCK); Snappy job.setoutputformatclass(sequencefileoutputformat.class); SequenceFileOutputFormat.setCompressOutput(job, true); SequenceFileOutputFormat.setOutputCompressorClass(job, SnappyCodec.class); SequenceFileOutputFormat.setOutputCompressionType(job, CompressionType.BLOCK); 14
1.4 맵출력데이터압축 튜닝대상맵리듀스잡 입력데이터크기 : 11G 작업유형 : 단순계산 (wordcount 성 ) Gzip 적용시압축을적용하지않았을때보다작업이지연되고, Snappy 적용시압축을적용하지않았을때보다작업시간이감소함 Gzip: 1 분 30 초지연 Snappy: 10 초단축 압축라이브러리적용결과비교 카운터 압축미적용 Gzip 적용 Snappy 적용 FILE_BYTES_READ 1,453,088,421 2,838,889 68,863,863 HDFS_BYTES_READ 11,966,801,064 11,966,801,064 11,966,801,064 FILE_BYTES_WRITTEN 2,219,075,754 8,391,610 109,038,190 HDFS_BYTES_WRITTEN 3,635 1,457 2,228 Reduce shuffle bytes 761,365,791 1,485,204 36,082,447 CPU time spent (ms) 1,013,810 1,347,100 990,840 Total committed heap usage 3,8565,642,240 38,536,019,968 38,570,033,152 15
2. DFS 블록사이즈수정 맵리듀스잡은수행되는맵태스크와리듀스태스크의개수에따라성능의영향을받게됨 같은사이즈의파일이라도더많은수의블록으로분리되면, 그만큼많은맵태스크가수행되어서빠르게작업이수행될것임 예제 ) 블록사이즈에따른예상맵태스크개수 입력파일블록사이즈 (dfs.block.size) 맵태스크수 100GB 32MB (100 * 1024) / 32 = 3200 100GB 64MB (100 * 1024) / 64 = 1600 100GB 128MB (100 * 1024) / 128 = 800 100GB 256MB (100 * 1024) / 256 = 400 16
2. DFS 블록사이즈수정 블록사이즈수정방법 Hdfs-site.xml 의 dfs-block-size 속성을수정 ( 기본값 : 64mb) distcp 코맨드를이용해 HDFS 에기등록된파일을새로운블록사이즈의파일을복사함./bin/hadoop distcp -Ddfs.block.size=[HDFS 블록사이즈 ] [ 입력경로 ] [ 출력경로 ]./bin/hadoop distcp -Ddfs.block.size=$[32*1024*1024] /user/hadoop/input/2008.csv /user/hadoop/input_32mb/2008.csv 32MB 블록으로구성된파일을대상으로잡을실행할경우, 64MB 블록으로구성된파일로잡을실행할때보다 2 배이상작업이지연됨 태스크트래커에서동시에실행할수있는맵태스크개수는한정되어있는데, 이러한값에대한수정없이맵태스크만과도하게실행했기때문임 17
2. DFS 블록사이즈수정 태스크트래커에서동시에실행할수있는태스크개수는다음과같음 파라미터기본값내용 mapred.tasktracker.map.tasks.maximum 2 mapred.tasktracker.reduce.tasks.maximu m 2 하나의태스크트래커에서동시에실행할수있는맵태스크의개수하나의태스크트래커에서동시에실행할수있는리듀스태스크의개수 맵태스크가 CPU 의 75% 이하를사용할경우최대맵태스크개수를 CPU 개수보다약간초과하게설정함 CPU 코어가 8 개일경우 : 맵태스크 8 개, 리듀스태스크 2 개혹은맵태스크 7 개, 리듀스태스크 3 개로설정함 하둡은적정리듀스태스크개수를 0.95 * 데이터노드개수 ~ 1.75 * 데이터노드개수 로권장함 18
2. DFS 블록사이즈수정 CPU 코어개수외에하드디스크구성, 입력데이터크기, 맵리듀스잡의분석유형등다양한요소를고려해야함 맵태스크의작업이단순해서수초내에완료되는경우블록사이즈조정이효과가있지만, 수십초이상소요될경우에는블록사이즈조정의효과가없음 태스크트래커는자신에게할당된태스크를주기적으로할당받는방식임 태스크수행시간이짧은경우는할당받는시간이오버헤드가되서튜닝효과가있지만, 태스크수행시간이긴경우에는할당받는시간이잡전체의수행시간에영향을주지않음 19
3. JVM 재사용 태스크트래커는맵태스크와리듀스태스크를실행할때마다별도의 JVM 을실행함 일반적으로사용자가인지하지못할만큼빠른속도로 JVM 이시작됨 맵사이드조인, 매퍼와리듀서의초기화시간이지연되는경우, 짧은시간안에많은매퍼를생성하는경우전체잡실행에영향을줄수있음 JVM 을재사용할경우태스크의시작시간을줄일수있음 mapred.job.reuse.jvm.num.tasks 속성값은 JVM 이실행할수있는최대태스크개수임. 기본값은 1 로설정되어있어, JVM 을재사용하지않음 mapred.job.reuse.jvm.num.tasks 속성값을 -1 로설정할경우 JVM 이실행할수있는태스크개수에제한이없어짐 20
4. 투기적인잡실행 투기적인 (speculative) 잡실행이란? 일정시간이지났는데도계속실행되는태스크가있으면, 해당태스크가실행되고있는데이터노드와다른데이터노드에서태스크를실행함. 기존태스크가먼저완료되면, 새로실행한태스크를강제종료하고, 새로실행한태스크가먼저완료되면, 기존태스크를강제종료함 파라미터기본값내용 mapred.map.tasks.speculative.execution mapred.reduce.tasks.speculative.executi on true true 잡이실행되는중다른맵태스크보다느리게동작하는맵태스크가있으면다른데이터노드에서해당맵태스크를실행합니다. 잡이실행되는중다른리듀스태스크보다느리게동작하는리듀스태스크가있으면다른데이터노드에서해당리듀스태스크를실행합니다. 21
4. 투기적인잡실행 기본값은 true 로설정되어있음. 잡인터페이스의 API 로설정변경이가능함 메서드 setspeculativeexecution setmapspeculativeexecution setreducespeculativeexecution 내용 job에서수행하는모든 task에대한투기적인실행옵션을설정합니다. job 에서수행하는 map task 에대해투기적인실행옵션을설정합니다. job 에서수행하는 reduce task 에대해투기적인실행옵션을설정합니다. 설정값을 false 로변경하고, 개별적인잡에대해서 true 설정하는것을권장함 태스크의로직에문제, HDFS 가아니라별도파일시스템에 read/write 를하는경우에투기적인실행이하둡클러스터에부하를줄수있음 22
5. DBMS 에데이터입력하기 리듀스태스크에서 DBMS 에데이터를입력하는경우장애가발생할수있음 투기적인 (Sepcualative) 잡이 true 로설정된경우 태스크 fail 로인하여자동 retry 가발생하는경우 성능과데이터정합성측면에서리듀스태스크에서 DBMS 에데이터를입력하는것은지양해야함 DBMS 에로딩할수있는파일을만들어서, DBMS 에로딩하는것을추천함 23