Hadoop 0.20 잠깐 봤는데 MapReduce 클래스가 모두 바뀌었네요. 기존에는 org.apache.hadoop.mapred 패키지였는데 org.apache.hadoop.mapreduce 라는 패키지가 만들어져 있고 기존의 org.apache.hadoop.mapred 패키지 대부분 클래스는 deplicate 되었습니다. Mapper 클래스도 기존의 configuration(), map(), close()가 아니라 setup(), map(), cleanup()으로 바뀌었네요. 기타 많이 바뀌었지만 일단 hadoop-0.20과 호환 가능하도록 Neptune의 MapReduceUtil 클래스를 조정해야 겠습니다. 아직 1.0은 아니라고 하지만 너무 심한 변화네요.
최근 Neptune의 부하 상황에 대해 지속적으로 테스트를 수행하고 있습니다. 부하 상황에서 다양한 오류가 발생하고 있는데 많은 부분이 Hadoop의 원인으로 나타나고 있습니다. hadoop을 단순히 MapRedude 작업용으로만 사용할 때에는 발생하지 않던 문제들이 실시간 Multi Thread 환경에서 사용되면서 다양한 문제가 나오고 있습니다. 그중 하나가 BlockReport 시간이 오래 걸리는 문제입니다. 다음 이슈에서 확인할 수 있습니다. https://issues.apache.org/jira/browse/HADOOP-4584 DataNode가 1시간 주기로 자기가 가지고 있는 모든 block 정보를 읽어 NameNode로 전송하는데 이 시간이 10분 이상 소요될 때도 있습니다. 문제는 이 시간 동안 다양한 lock이 발생하면서 NameNode에서는 해당 DataNode가 죽은 것으로 판단하기도 하고 DataNode 자체에서는 디렉토리 생성, 파일 읽기 작업 등에 문제가 발생하기도 합니다. 두번째 문제는 Hadoop의 DataNode가 동시에 서비스 가능한 Block의 갯수의 제한입니다. default 값은 256개입니다. 파라미터로 수정 가능하지만 hadooop-default.xml 에는 나와 있지 않고 소스에서 찾아야 합니다. Property 이름은 "dfs.datanode.max.xcievers" 입니다. 무작정 늘릴 수는 없고 허용 가능한 Socket 갯수 정도로 지정하면 됩니다. 일단 Neptune에서는 이런 문제에 대해 Neptune의 성능을 조금 다운그레이딩 하는 차원에서 해결할려고 합니다. Hadoop을 수정할 수는 없으니까요...
마지막으로 이런 문제들이 주로 DataNode가 수행되는 노드에 hdfs를 사용하는 프로그램(TabletServer 등)을 수행했을 때 많이 발생하였습니다. 사용한 Hadoop 버전은 0.19.0 입니다.
HBase0.20에서는 Master Server의 Failover를 위해 ZooKeeper를 사용하는 부분과 성능 개선 크게
두분에 중점을 두었다고 합니다. "HBase goes realtime" 발표 자료 제목에서 보듯이 성능을 크게 향상 시켰다고
합니다.
Cache를 사용하지 않고 Sequential write 성능이 1 row 당 0.024ms 라고 합니다. 0.19에서는 클라이언트 측
Cache에 대한 속임수가 있었는데(http://www.jaso.co.kr/321 참고) 발표자료에서 Uncached라고 명시
되어 있네요. 이 발표 자료도 처음 보았을 때는 Wow!!! 하며 깜짝 놀랐습니다. 1 row 처리하는데 0.24ms도 아닌
0.024ms, 다시 말해 1초에 40,000 TPS 정도의 성능입니다.
테스트 환경이나 테스트 데이터에 대해 나와 있지 않지만 기존 테스트 코드를 참조해서 1 record = 1000 byte라고
했을 때 0.24ms 이면 bandwidth로 하면 40MB/sec 정도입니다. 일반적으로 SATA 디스크의 경우 70MB ~
90MB/sec이고 1Gbps 네트워크의 100MB/sec 정도인 것을 생각하면 0.024ms라는 수치는 정상적인 수치는
아니라는 생각이 듭니다. 확인할 수 있는 방법은 테스트 코드를 돌려보는 수 밖에 없겠네요...
------------------------------------------------------------------- 조금 더 찾아 보니 1 record가 1000byte가 아니라 16 byte라고 합니다. bandwidth로 하면 650KB/sec 정도네요... 그리고 random write가 아니라 sequential write인 것을 보면 RPC로 통신하면서 row 당 한번의 call로 하는 것이 아니라 neptune의 uploader와 비슷하게 한번에 쭉 밀어 넣는 방식으로 처리하는 것이 아닐까 하고 추측해 봅니다. 정확한 건 코드를 봐야 겠죠. ㅋㅋㅋ
hadoop을 구성하는 데몬 서버 중에 Secondary NameNode 라는 것이 있습니다. 최근 이놈 때문에 고생을 좀 했습니다. ㅋㅋㅋ Secondary라는 이름만 보면 NameNode의 stand-by 역할을 수행하거나 백업 역할을 수행하는 것입니다. 하지만 실제로는 Stand-by 역할을 수행하지 않고 NameNode에서 관리하는 파일시스템의 이미지 정보를 백업하는 기능을 수행합니다. 하지만 또 다른 기능을 수행하는데 이것이 아주 중요한 기능입니다. NameNode의 Hadoop 파일시스템의 이미지 정보를 저장하고 있는 파일과 파일생성, 디렉토리 생성 등과 같은 작업을 수행한 edit log를 머지하는 작업을 Secondary NameNode 가 수행합니다. 이 작업을 하지 않아도 Hadoop 시스템에 큰 문제는 발생하지 않습니다. 따라서 Secondary NameNode 설정이 잘못되어서 운영되지 않아도 당장은 큰 문제가 없습니다(물론 Secondary NameNode가 동작하지 않거나 실행하지 않은 경우라면 NameNode의 hadoop 파일시스템 이미지 파일은 rsync 등을 통해 주기적으로 백업을 받아야 겠죠.) 문제는 Hadoop을 오랜 기간동안 stop 시키지 않았거나 파일 시스템에 많은 작업(수십만 번의 파일생성, 삭제, 디렉토리 생성 등)을 수행한 경우 Hadoop을 중지 했다가 다시 실행할 경우에 발생합니다. Secondary NameNode에서 수행해야 할 edit log 파일과 머지하는 작업이 수행되지 않았기 때문에 edit log 파일에 엄청나게 많은 로그가 쌓여 있게 됩니다. hadoop이 시작될때 처리는 먼저 이미지 파일을 읽어 메모리에 기본 파일시스템의 inode 정보를 구성한 다음에 edit log 파일을 읽어 순차적으로 실행합니다. 이 과정이 모두 완료되어야만 클러스터가 ready 상태가 됩니다. 하지만 수행해야할 edit log 레코드가 많은 경우라면 수행 속도도 느리고 메모리도 그 만큼 많이 차지하게 됩니다. 제 경우에 기존에 4GB 메모리에서도 잘 운영되는 클러스터가 restart 할 경우 16GB로 늘려야지만 겨우 다시 정상적으로 구동이 되었습니다. 그것도 몇 시간 클러스터 startup 과정을 거친 후에 말입니다.
따라서 Secondary NameNode는 단순 백업용이 아니라 아주 중요한 역할을 수행하고 있기 때문에 반드시 정상적으로 운영되고 있는지 모니터링 되어야 합니다. 주기적으로 edit log 파일이 과도하게 증가하지 않는지 점검해보는 것도 클러스터를 안정적으로 운영하는 방법중 하나입니다.
최근 Hadoop의 MapRecuce 작업을 이용하여 BI, DW에 적용하는 시도가 많이 이뤄주고 있는 것 같습니다. Hive, Cloudbase 등과 같은 솔루션은 SQL 문을 이용하여 mapreduce 작업을 쉽게 실행할 수 있도록 해줍니다. SQL문과 map reduce의 관계는 다음과 같이 매핑할 수 있습니다.
select sum(ip) into t_result from t_log where log_date = '20090601' group by ip
select column -> map output value sum -> reduce function into -> output path from -> input path where -> map function group by column -> map key