'HBase' 태그의 글 목록
www.recopick.com

안녕하세요. RecoPick팀의 김성민 입니다.


이번 글에서는 HBase를 사용하면서, 궁금했던 점들 몇 가지를 질의 응답 형식으로 정리해 봤습니다.

FAQ와 다르게 자주하는 질문들이 아닌 것 같아서, 제목을 IAQ[각주:1]라고 했습니다.


Q1. HBase의 .META. 테이블도 split 될까?

A1. 안됨

HBase의 .META. 테이블은 region 정보를 저장하고 있는 특별한 테이블인데, BigTable 논문에서 .META. 테이블이 여러 region으로 나눠질 수 있도록 설계했지만, HBase에서는 .META. 테이블은 split 되지 않도록 구현했습니다. 그리고, -ROOT- 테이블은 .META. 테이블이 저장된 region 정보를 가지고 있기 때문에, split 되지 않습니다. 하지만, HBase에서는 .META. 테이블이 split 되지 않기 때문에, 0.94 이후 버전 부터는 -ROOT- 테이블을 없애고, .META. 테이블만 사용하도록 변경하였습니다.


.META. 테이블에 모든 region의 메타 정보(데이터가 저장된 위치 정보)를 저장하고, .META. 테이블이 split 되지 않기 때문에, HBase 클러스터는 최대 1개의 region에 저장할 수 있는 메타 정보 개수 만큼의 region을 저장할 수 있습니다. 즉, HBase 클러스터를 무한히 크게 할 수 없습니다.




Fig 1-(a). .META. 테이블 구조



Fig 1-(b). Zookeeper와 .META. 테이블 구조





Fig 1-(c). BigTable의 root, meta 테이블 구조


Q2. (minor/major) compaction 작업은 서로 다른 region들 사이에서도 진행되는가?

A2. 안됨.

HBase에서는 주기적으로 데이터 사이즈가 작은 파일들을 하나로 합쳐주는 compaction 작업을 진행합니다. 데이터를 저장할 때, 자동으로 split 해서 저장했다가, 파일 크기가 작은 파일들이 많이 생길 경우, 하나의 큰 파일로 합쳐주는 작업을 진행하는데, compaction 작업의 단위는 directory가 아니라 file 단위이기 때문에, 서로 다른 region에 있는 작은 파일들을 하나로 merge하지는 않습니다.

HBase에서 region은 HDFS상에서 하나의 directory를 의미하고, compaction의 동일한 region 즉, directory 내에 있는 파일들을 하나의 큰 파일로 합쳐주는 작업이라고 이해하시면 됩니다.




Fig 2. Minimum compaction threshold


Q3. HBase에서 저장하고자 하는 테이블(region)을 미리 split 한 후, 데이터를 저장할 때, major compaction이 시작되면, 데이터(HFile)가 없는 테이블(region)은 삭제 되는가?

A3. 안됨.

HBase에서는 write 연산이 빈번하게 연속적으로 발생할 경우, region split 역시 빈번하게 발생 하기 때문에, 미리 region을 split 해서 write할 때, region이 split되는 것을 회피해서 write 성능을 향상 시키는 방법을 종종 사용합니다. 그런데, 실제 write 연산을 수행하기 전에 region을 split 하는 것이기 때문에, 실제 데이터는 존재하지 않고, .META. 테이블에 rowkey와 region server 정보가 기록되어 있습니다. 이후, write 연산을 수행하면, 저장할 데이터의 row key가 미리 split한 region에 start과 end row key 범위에 들어있지 않은 경우, 특정 region에는 데이터가 전혀 존재하지 않을 수 있습니다. 이렇게 되면, major compaction을 할 때, region의 데이터 사이즈가 작기 때문에, 데이터가 존재하지 않은 region은 삭제 될 것 같다고 추측할 수 있습니다. 하지만, Q2에서 설명한 것 처럼, compaction은 여러 파일들을 하나로 합치는 작업이지 디렉터를 하나로 합치는 작업이 아닙니다. 따라서, region은 일종의 디렉터리이기 때문에, 데이터 즉, 파일을 하나도 가지고 있지 않은 region (비어 있는 디렉터리)들을 compaction 작업 시, 하나로 합치거나 삭제 되지 않습니다.




Fig 3. HBase Architecture - Storage


Q4. Region이 split 될 때, region의 데이터 크기를 기준으로 split 되는지, 아니면, region 내의 row key의 최소, 최대 값을 기준으로 하는지?

A4. 설정에 따라 다름.

Region을 split하는 정책은 "hbase.regionserver.region.split.policy" 라는 설정에 따라서, 결정됩니다.

0.94 이전 버전에서는 region이 데이터 크기를 기준으로 split 했지만, 이후에는 defalut 설정이 변경되었습니다.

다음과 같은 미리 정의된 Split policy가 있습니다. (물론, custom split policy를 구현하실 수도 있습니다.)


(1) ConstantSizeRegionSplitPolicy

(2) IncreasingToUpperBoundRegionSplitPolicy

(3) KeyPrefixRegionPolicy

(4) DelimitedKeyPrefixRegionSplitPolicy

(5) DisabledRegionSplitPolicy




Fig 4. HBase Region splitting


Q5. WAL (Write Ahead Log) 를 disable 시킨 상태에서 write을 수행 중이던 region server가 crash 될 경우, crash 이전까지 write한 데이터는 HBase에 저장되었을까?

A5. 알수 없음.

HBase에서 write 연산을 수행하면, WAL(HDFS)와 Memstore(Memory)에 데이터를 기록하는데, WAL을 사용하지 않을 경우, Memstore에만 데이터를 쓰고, Memstore에 더 이상 데이터를 쓸 수 없을 경우나, 혹은 일정 시간 간격으로 Memstore에 있는 데이터를 HDFS에 강제로 기록합니다. 그런데, 만약, Memstore의 데이터가 HDFS에 flush 되지 않은 시점에 region server가 crash된 경우, 메모리 상에 있는 Memstore 데이터가 사라지기 때문에, region server가 crash 되기 전에 write 한 데이터가 정상적으로 저장되었다고 확신할 수 없습니다.

만약, WAL을 사용했다면, 새로운 region server가 실행 되면서, WAL를 replay 하기 때문에, region server가 crash 되기 전의 데이터가 정상적으로 저장됩니다.




Fig 5-(a). HBase Write Path



Fig 5-(b). HBase Write Sequence Diagram



[참고 자료]

Q1. (1) http://blog.cloudera.com/blog/2013/04/how-scaling-really-works-in-apache-hbase/ 

       (2) https://blog.safaribooksonline.com/2012/11/16/tip-2-hbase-meta-layout/

(3) http://research.google.com/archive/bigtable.html


Q2. (1) http://hbase.apache.org/book.html#compaction


Q4. (1) http://hortonworks.com/blog/apache-hbase-region-splitting-and-merging/

       (2) http://hbase.apache.org/book/config.files.html#hbase.regionserver.region.split.policy


Q5. (1) http://hbase.apache.org/book/config.files.html#hbase.regionserver.optionalcacheflushinterval

       (2) http://www.slideshare.net/enissoz/hbase-and-hdfs-understanding-filesystem-usage

       (3http://blog.sematext.com/2012/07/16/hbase-memstore-what-you-should-know/

(4http://blog.cloudera.com/blog/2012/06/hbase-write-path/

(5http://www.larsgeorge.com/2010/01/hbase-architecture-101-write-ahead-log.html

 

  1. Peter Norvig의 Java IAQ에서 제목을 인용함(http://norvig.com/java-iaq.html) [본문으로]
Posted by recopick
TAG HBase

댓글을 달아 주세요

안녕하세요. RecoPick팀 김성민입니다.

오늘은 최근 RecoPick팀에서 DynamoDB를 사용하게 되면서 배웠던 사항을 QnA 형태로 정리했습니다. 참고로 그동안 제가 주로 HBase를 사용해왔기 때문에, 되도록 DynamoDB와 HBase를 비교하면서 설명해 보도록 하겠습니다.

1. HBase와 DynamoDB의 개념적인 차이?

  HBase와 DynamoDB의 개념적인 차이를 한마디로 말하자면, SortedMap(a.k.a TreeMap)과 HashMap의 차이점과 같습니다. java TreeMap은 element가 정렬되어서 저장되어 있으나, HashMap의 경우, 저장된 element의 정렬 순서를 보장하지 않습니다. 마찬가지로 HBase의 경우, 저장되는 데이터가 모두 alpha numeric 순서 정렬되어 있으나, DynamoDB는 저장되는 데이터의 정렬 순서를 보장하지 않습니다. 


2. HBase와 DynamoDB의 구조적인 차이?

  HBase는 Master-Slave 구조지만, DynamoDB는 Peer-To-Peer 구조로 되어 있습니다. 아래그림 처럼, HBase는 논리적으로 B+Tree 구조로 데이터를  분산해서 저장하지만, DynamoDB는 consistency hash 방식을 사용해서 저장합니다.


그림 1. Table location hierarchy



그림 2. Partitioning and replication of keys in Dynamo ring.


3. Eventually Consistent vs Strongly Consistent?

  DynamoDB의 경우,  eventually  consistent reading과 strongly consistent reading을 모두 지원하지만, Scan 연산의 경우는 eventually consistent reading만 지원합니다. (참고로, strongly consistent reading은 항상 최종 변경 내용을 반환해 주지만, eventually consistent reading은 최종 변경 내용을 항상 반환해 줄 수는 없다는 뜻입니다.)


4. Range query를 수행할 수 있는지?

  앞서 HBase와 DynamoDB의 개념상 차이에서 설명한 것처럼, DynamoDB는 개념적으로 정렬 순서를 보장하지 않는 HashMap이기 때문에, DB layer에서 range query를 지원하지 않습니다. 그럼에도 불구하고, DynamoDB에서 range query를 사용해야 한다면, 아래와 같은 방법을 고려 해 볼 수 있습니다.

  먼저 데이터 접근 패턴(access pattern)을 분석해서, DynamoDB의 키를 계층 구조로 설계하고, 동일한 키에 대해서 range query를 수행할 수 있도록 스키마를 설계해야 합니다.

  예를 들어, 1~100 사이 값을 unique id로 갖는 데이터를 저장할 때, 이 값을 그대로 key로 사용하면, DynamoDB에서는 "13~25의 값을 꺼내"와 같은 range query는 수행할 수 없습니다. 이를 우회하기 위해, 1~100 사이의 unique id를 10단위로 해서 아래와 같이 그룹핑을 한 후,



Group Id를 Hash Key로 하고, Unique Id를 Range Key로 설정해서 저장합니다. 

만약 id가 13~25 사이의 데이터를 가져오는 range query를 수행하고자 한다면, 먼저 해당 Unique Id들이 포함되는 Group Id들(이 경우에는 11, 21)를 찾습니다. 그리고 Group Id 11을 hash key로 갖는 데이터 중에서 unique id가 13~20 사이에 있는 데이터를 가져오는 query를 수행 합니다. 마찬가지로 Group Id 21을 hash key로 갖는 데이터 중에서 unique id가 21~25 사이에 있는 데이터를 가져오는 query를 수행해서 Unique Id가 13~25 사이의 데이터를 가져올 수 있습니다. 즉, DB에서는 지원하지 않지만, 스키마를 잘 설계하면, application layer에서 range query를 흉내내는 것은 가능합니다.


5. Secondary Index를 지원하는가?

  HBase의 경우 secondary index를 지원하지 않습니다. 따라서 Secondary index를 별도의 테이블로 생성해서 직접 관리해 줘야 하는 부담이 있습니다. 반면에, DynamoDB는 Local/Global Secondary Index 2가지를 지원하고 있습니다. 

  Local Secondary Index는 메인 테이블과 별개로 테이블이 생성되는 것은 아니고, 데이터를 저장하는 물리적인 node의 local storage에 색인 데이터가 생성되는 것입니다. 그리고 Local Secondary Index의 경우, 최대 10GB까지 데이터를 저장할 수 있습니다. 

  하지만 Global Secondary Index는  메인 테이블과 별개로 새로운 테이블이 생성되고, 메인 테이블의 일부 item들을 projection한 결과를 저장할 수 있습니다. 또한, Global Secondary Index는 메인 테이블의 내용이 변경될 경우, 데이터를 자동으로 동기화되는 장점이 있습니다.

  DynamoDB의 Secondary Index 기능은 매우 좋은 기능이지만, 다음과 같은 단점도 존재합니다.

 a. Loca/Global Secondary Index를 각각 테이블당 최대 5개까지 밖에 생성할 수 없습니다. 

 b. 테이블을 생성할 때, Secondary Index를 생성해 줘야 하며, 테이블 생성 완료 후, 변경이 불가능합니다. 만약 테이블이 생성된 후, Secondary Index를 추가하고 싶다면, 다른 테이블을 만든 다음, 데이터를 모두 옮겨줘야 합니다.

 c. Secondary Index가 추가될 때마다, write capacity가 감소합니다. 만약 Secondary Index가 없다면, 테이블에 1회 write operation을 수행한다면, 1번의 write만 일어나지만, Secondary Index가 있다면, Secondary Index 개수만큼 write가 추가적으로 발생하게 됩니다. 따라서 동일한 write capacity 상에서 Secondary Index를 추가할수록 사용 가능한 write operation은 그만큼 줄어들게 됩니다. (=돈이 많이 듭니다) 그러므로 불필요한 Secondary Index는 되도록 만들지 않는 것이 신상에 좋습니다.


6. Schema 변경이 자유로운가?

  DynamoDB 역시 다른 NoSQL 처럼, schemaless 하므로, schema 변경은 자유롭습니다. 하지만 하나의 테이블에 저장되는 item의 크기 (RDS의 row size와 같음)에는 64KB를 초과할 수 없습니다. HBase의 경우, 이론상 하나의 row에 저장할 수 있는 column 수에 제한이 없지만, DynamoDB의 경우, 한 item에 저장되는 데이터의 크기가 64KB를 넘지 않도록 주의해야 합니다.


7. TTL(Time-To-Live)을 지원하는가?

   HBase의 경우, TTL을 설정해서 일정 기간 이상 지난 오래된 데이터는 자동 삭제할 수 있도록 할 수 있지만, 현재까지 DynamoDB는 TTL을 지원하고 있지 않습니다. 많은 사용자들이  TTL 기능을 요구하고 있지만, 아직 AWS DynamoDB Team에서 지원해주지 못하고 있다고 합니다.

   따라서 TTL 기능이 필요한 경우, last modified time 과 같은 속성을 데이터에 추가해서 오래된 데이터는 사용자가 직접 삭제할 수밖에 없습니다. 로그 데이터와 같은 Time Series Data의 경우에는 일별, 주별 혹은 월별로 테이블을 별도로 생성한 후에, 오래된 데이터는 테이블 전체를 삭제하는 하는 편이 더 좋다고 합니다. 만약, 테이블을 시간 순서로 분리하지 않고, 하나의 테이블에 있는 오래된 데이터를 삭제할 경우, 삭제 연산 역시 write 연산이기 때문에 그만큼의 write capacity가 필요하고, 테이블 전체를 삭제하는 것보다 비효율적이라고 합니다.


8. Transaction을 지원하는가?

  MySQL과 같은 RDS를 사용하다가 HBase나 DynamoDB와 같은 NoSQL을 사용할 때, 가장 먼저 겪는 불편함은 mult-rows혹은 mutl-tables 간의 transaction 처리 일 것입니다. 대부분의 NoSQL은 scalibility를 위해서 transaction을 희생하고 있기 때문에, application개발 시에, transaction 이 필요하다다면, 난감한 상황에 처하게 됩니다.

  다행히 DynamoDB의 경우, mutl-rows transaction을 지원하는 java API를 제공하고 있습니다. Transaction 처리가 필요한 경우, 한 번쯤 검토를 해보시는 것도 좋을 것 같습니다. HBase의 경우, omidhaeinsa와 같은 transaction 기능을 지원하는 open source project가 진행 중이니 참고 하시기 바랍니다.


9. Multi-versioning 기능을 제공하는가?

   HBase의 경우, MAX_VERSION이라는 옵션을 사용해서, 여러 버전의 데이터를 저장할 수 있습니다. 예를 들어, MAX_VERSION을 3으로 설정하면, 동일한 row key에 대해서 최대 3개까지의 데이터를 저장하고, 버전별로 데이터를 읽어올 수 있습니다.

  DynamoDB의 경우, 아쉽게도 mult-versioning 기능을 지원하지 않기 때문에, (물론 내부적으로 multi-version을 이용해서 데이터를 관리합니다.) multi-versoning 기능이 필요한 경우, TTL과 마찬가지로 사용자가 직접 관리해줘야 하는 부담이 있습니다.


10. 쉽게 확장 가능한가?

  DynamoDB는 provisioned I/O를 보장해 주기 때문에, read/write throughput  필요에 따라서 scale-up 하기가 쉽습니다. AWS DynamoDB Console이나 Client API를 이용해서 쉽게 read/write throughput을 조정할 수 있습니다.

  하지만 scale-up은 임의대로 할 수 있지만, scale-down은 1일 4회로 제한되어 있습니다. 따라서 read/write peek 시점에만 일정 시간 동안 scale-up을 했다가, 다시 scale-down을 하고자 할 경우, 하루에 5번 이상 할 수 없습니다. 이런 경우에는 read/write 모니터링을 하면서, read/write 횟수를 일정하게 유지 할 수 있도록 시스템을 설계하는 것이 좋습니다. 그렇지 않을 경우, 요금 폭탄을 맞을 수도 있습니다. 

이상 10가지 정도 DynamoDB에 대해서 HBase와 비교하여 간략히 설명해 드렸습니다. DynamoDB의 경우, HBase가 지원하지 않는 좋은 장점들도 있지만, 데이터 모델의 차이 때문에 데이터의 접근 패턴에 따라서는 사용하기 어려운 부분도 있습니다.

언제나 그렇듯 정답은 없는 것 같습니다. 너무 뻔한 얘기지만, 역시 NoSQL을 사용하고잘 할 때는 NoSQL 마다의 특성을 잘 파악해서 사용 목적에 가장 잘 맞는 것을 선택해서 사용하는 것이 정답인 것 같습니다. ^^


[참고 자료]


Posted by recopick

댓글을 달아 주세요

안녕하세요. RecoPick팀 김성민입니다.

hadoop으로 map-reduce 작업을 수행할 때, 작은 크기의 파일들이 많을 경우, 어떤 문제점이 있고 이러한 문제점을 hadoop에서 어떻게 해결할 수 있는지 간략하게 정리해 봤습니다.

일반적으로 로그 데이터를 처리하는 경우, 대부분 시간 단위로 저장되는 데이터이기 때문에, 작은 크기의 로그 파일들이 많이 생겨납니다. 이러한 로그 데이터처럼, 크기는 작지만, 파일 개수가 많은 데이터를 map-reduce 작업으로 처리하고자 할 경우, map task는 최소 파일 개수 만큼 생성됩니다. 


원래 hadoop에서는 입력 데이터를 일정한 크기(기본은 HDFS block 크기인 64MB)로 나눠서 input split (이하 block이라고 함)을 생성한 다음, map task를 실행합니다. 하지만 하나의 파일의 크기가 block 크기보다 작더라도, 다른 파일의 데이터를 읽어서 나머지 block 크기만큼의 데이터를 채워서 하나의 map task에서 처리 하도록 하지는 않습니다. 크기가 작은 파일이더라도, 파일 하나당 하나의 map task가 생성되고, map task들은 적은 입력 데이터만 처리하고 종료하게 됩니다. 

 
예를 들어, 하나의 서버에서 동시에 2개의 map task처리할 수 있고, 이러한 서버 다섯 대로 구성된 hadoop 클러스터가 있다고 가정하면, 한 번에 실행될 수 있는 최대 map task 수는 (장비 당 최대 실행 가능한 map task 수) x (Task Node 수) = 2 * 5 = 10 개입니다. 그런데 10분 간격으로 로그 데이터( < 64MB 작은 파일들)를 저장할 경우, 1시간에 6개, 1일이면, 144개의 로그 파일들이 생성됩니다.


앞서 가정한 hadoop 클러스터에서 1일 동안의 로그 분석을 하고자 한다면, 결국 최소 144개의 map task가 필요합니다. 결국, 1일 데이터를 처리하는 동안 사용 가능한 최대 map task slot을 모두 차지하게 되므로, 다른 map-reduce 작업을 스케줄링하는데 어려움이 생기게 됩니다.


그리고 map task가 한번 실행되고, 종료 될 때 마다, map task 당 jvm이 한 번씩 실행되고, 종료되기 때문에 jvm이 실행되고 종료되는 시간이 전체 작업 시간을 지체시킬 수 있습니다. (물론, jvm을 재사용 옵션 mapred.job.reuse.jvm.num.tasks을 사용하면, 이런 문제는 피할 수 있습니다.)


또한, hadoop의 HDFS에 저장되는 모든 파일의 메타 정보들은 name node의 메모리에 저장되는데, 파일 개수가 많아지면, name node의 메모리를 더 많이 사용하게 되고, disk 공간은 남아 있음에도 불구하고, name node의 메모리가 부족해서 더 이상 파일을 저장할 수 있는 상황도 발생할 수 있습니다.

그렇다면, 이런 작은 크기의 파일들을 어떻게 하면 효과적으로 hadoop에서 처리 할 수 있을까요?

가장 쉽게 떠오르는 아이디어는 크기가 작은 파일들이 여러 개 존재하는 것이 문제이므로, 여러 개의 작은 파일들을 최소한 block 크기보다 크게 합쳐서 저장하는 방법을 생각할 수 있습니다. 


조금 더 구체적으로 적어보면,

  1. 처음부터 HDFS에 데이터를 기록할 때, 하나의 파일에 계속 append 하는 방식으로 작은 크기의 파일을 하나로 합치는 방법
  2. 주기적으로 여러 개의 작은 파일들을 하나로 합치는 별도의 작업을 실행해서 하나의 큰 파일로 만드는 방법
  3. hadoop archive 파일 (har)을 이용하는 방법
등을 떠올릴 수 있습니다.


그런데 로그 데이터와 같은 시간 단위 데이터를 저장하기 할 때,


  • clicklog.2013-12-05_0700
  • clicklog.2013-12-05_0800
  • clicklog.2013-12-05_0900
  • clicklog.2013-12-05_1000
  • clicklog.2013-12-05_1100
  • clicklog.2013-12-05_1200


위 와 같이 한 시간 단위로 나눠서 저장하는 대신, 


  • clicklog.2013-12-06
  • clicklog.2013-12-07
  • clicklog.2013-12-08
  • clicklog.2013-12-09
  • clicklog.2013-12-10


위와 같이 대용량의 파일(하루 단위)로 모아서 저장할 경우, 일정 기간(12/5 7시~10시까지)의 데이터만 필요한 경우에는 데이터를 다시 분리를 해야 하기 때문에 불편할 수 있습니다.


이런 경우를 대비해서 파일 이름(시간 및 날짜 정보)을 키로 하고, 파일 내용 전체를 값으로 해서 sequence file 혹은 map file 형태로 저장하면, 여러 개의 작은 파일들을 하나의 큰 파일로 저장할 수 있으면서도, 필요한 만큼의 데이터를 쉽게 찾을 수 있습니다. 특히, sequence file을 사용할 경우, block 단위로 압축할 수 있기 때문에, 더욱 많은 작은 파일들을 효과적으로 하나의 큰 파일로 만들 수 있습니다.

지금까지는 작은 파일들을 하나의 큰 파일로 합치는 방법을 생각해 보았습니다. 그런데 작은 파일들을 하나의 큰 파일로 합치기 위해서 별도의 작업을 하는 것이 번거로울 때가 있습니다. 특히, 일회성 데이터를 분석을 위해 이런 방법을 써야 한다면, 데이터 분석 작업 보다 데이터를 준비하는 작업이 더 오래 걸릴 수 도 있습니다.

그렇다면, 작은 파일들을 합치지 않고, map-reduce 작업을 할 때, 불필요하게 많은 map task가 수행되지 않는 방법은 없을까요?


hadoop의 map-reduce 작업 수행 시, 여러 개의 파일이 하나의 map task의 입력으로 사용되지 않기 때문에, 최소한 파일 개수만큼 map task 작업이 수행됩니다. 반대로 생각하면, 만약, 단일 map task의 입력 데이터로 여러 개의 파일을 사용할 수 있다면, 총 파일 개수보다 더 작은 수의 map task로 map-reduce 작업을 수행할 수 있게 됩니다.


hadoop의 map task는 기본적으로 TextInputFormat이라는 클래스를 이용해서 입력 데이터를 읽어오는데, 여러 개의 파일을 하나의 입력으로 읽어올 수 있는 InputFormat 클래스가 있다면, 작은 파일들을 하나로 합치지 않고도 적정한 개수의 map task 수를 유지하면서 map-reduce 작업을 수행 할 수 있지 않을까요?

이런 요구 사항에 딱 맞는 CombineFileInputFormat이라는 클래스가 있습니다. 하지만 CombineFileInputFormat 클래스는 추상 클래스이므로, 자신의 상황에 맞게 직접 구현해서 사용해야 합니다. 최근에 Process Small Files on Hadoop Using CombineFileInputFormat 이라는 블로그 포스트에서 CombineFileInputFormat 클래스에 대한 구현 예제와 성능 실험에 대한 내용이 공유되었으니, 구현 시 참고하시면 좋을 것 같습니다.


CombineFileInputFormat 클래스는 사용하면, 너무 많은 map task가 수행되는 문제점은 해결 할 수 있지만, name node 메모리 문제는 여전히 남아 있습니다. 


앞서 설명한 네 가지 방법들을 사용하면, 두 가지 문제를 모두 어느 정도까지는  해결 할 수 있지만, 여전히 작은 파일들을 하나로 합치기 위한 별도의 작업이 필요하다는 점에서는 조금 귀찮은 부분이 있습니다.

너무 많은 개수의 map task 수와 name node 메모리 문제를 모두 해결하기 위해서 저희 팀에서 선택한 방법은 데이터를 hbase에 저장하는 방식입니다.

hbase는 처음부터 HDFS의 기본  block 크기(64MB)보다 더 작은 크기의 데이터를 저장하기 위해서 설계되었으므로, 작은 파일들을 효율적으로 저장할 수 있습니다. 따라서 작은 파일들을 저장하기 위해서 하나의 큰 파일로 합치는 별도의 작업을 할 필요가 없습니다.


또한, 로그 데이터처럼 시간 단위로 데이터를 저장해야 할 경우, hbase의 row key를 시간으로 설정하여 저장하면, 필요한 범위의 시간 데이터를 쉽게 가져올 수 있기 때문에, 파일로 저장했을 때보다 데이터 접근이 조금 더 편리 해 집니다.

hbase 데이터로 map-reduce 작업을 수행할 때, map task 수는 입력 데이터를 가지고 있는 region 개수만큼 실행됩니다. 그래서 region 개수를 작게 하면, 불필요하게 많은 map task 생성되는 것을 피할 수 있습니다. region 개수는 데이터 크기 즉, 저장되는 row 수와 비례하지만, hbase 테이블 설계나 설정을 통해서 적절한 개수를 유지할 수 있기 때문에 HDFS에서 매번 작은 파일들을 하나로 합치는 작업을 하는 것보다는 관리가 쉽습니다.

지금까지 얘기한 작은 크기의 파일들을 하둡에서 효과적으로 처리하는 방법을 요약하자면, 다음과 같습니다.


  1. hdfs에 저장할 때, 파일 내용을 append하는 방법
  2. 작은 파일들을 하나로 합치는 작업을 주기적으로 실행하는 방법
  3. hadoop archive (har) 파일을 이용하는 방법
  4. 파일 이름과 파일 내용을 각각 키와 값으로 해서 sequence file로 저장하는 방법
  5. CombineFileInputFormat을 이용해서 맵 리듀스 작업을 수행하는 방법
  6. HBase에 데이터를 저장하는 방법



[참고 자료]

The Small Files Problem


File Appends in HDFS

Hadoop Archive: File Compaction for HDFS

Process Small Files on Hadoop Using CombineFileInputFormat


Hadoop I/O: Sequence, Map, Set, Array, BloomMap Files

Hadoop: The Definitive Guide (3rd Edition) Ch 7. MapReduce Types and Formats - Processing a whole file as a record


filecrush - a highly configurable tool by Edward Capriolosmall files on HDFS


Dealing with hadoop's small files problem












Posted by recopick

댓글을 달아 주세요

  1. 하둡 2014.04.03 12:18 신고 Address Modify/Delete Reply

    좋은 내용 감사합니다 :-)