Apache Hadoop — 1つのPodにHDFSとYARNを立てて運用する
小さなファイル 2,000 個をアーカイブにまとめ、NameNode のオブジェクト数を測る
한국어 원문으로 표시합니다.
목표
센서 CSV 2,000개(파일 하나에 수백 바이트)를 HDFS 에 올려 NameNode 가 들고 있어야 하는 객체(파일·디렉터리·블록)가 몇 개인지 재고, 하둡 아카이브(HAR)로 묶어 그 수가 얼마나 주는지 본다. 묶은 뒤에도 har:// 로 원래 파일을 하나하나 읽을 수 있는 것과, distcp 로 아카이브를 통째로 옮기는 것까지 해 본다.
왜 중요한가
NameNode 는 파일·디렉터리·블록 하나하나를 자바 객체로 힙에 들고 있다. 파일이 1바이트든 1GB 든 객체 수는 같다. 그래서 HDFS 의 한계는 대개 디스크가 아니라 NameNode 의 힙이고, 수백만 개의 작은 파일은 디스크를 거의 쓰지 않으면서 NameNode 를 먼저 쓰러뜨린다. 맵리듀스·Spark 입장에서도 작은 파일은 파일마다 태스크나 열기 비용이 붙어 느리다.
해법은 파일을 덜 만드는 것이다 — 쓸 때 모아서 쓰거나(Spark 의 repartition·coalesce, 큰 컨테이너 파일 형식), 이미 생긴 것을 묶는다. HAR 은 뒤쪽 방법이다. 많은 파일을 큰 파일 몇 개(part-*)와 색인(_index·_masterindex)으로 바꿔 NameNode 의 객체 수를 줄이고, 읽을 때는 har:// 파일 시스템이 색인을 보고 원래 경로로 찾아 준다. 대신 한 번 만든 아카이브는 고칠 수 없다(읽기 전용).
이 실습은 아카이브와 distcp 를 YARN 없이 로컬 실행기로 돌린다. 둘 다 맵리듀스 잡이지만 실행 위치는 설정 하나로 바뀐다 — 같은 잡이 노트북에서도 클러스터에서도 돈다.
단계
/data/small디렉터리(파일 2,000개)를 HDFS /user/root/small/raw 로 올리세요(hdfs dfs -put -t 8로 여러 줄기로 올리면 빠릅니다).- raw 의 파일 수·디렉터리 수·블록 수를 /root/hdp/small/objects.json 에
{"raw_files": 정수, "raw_dirs": 정수, "raw_blocks": 정수}로 쓰세요. hadoop archive -D mapreduce.framework.name=local -archiveName raw.har -p /user/root/small -r 1 raw /user/root/small/archive로 아카이브를 만드세요.hdfs dfs -ls -R har:///user/root/small/archive/raw.har로 아카이브 안의 파일 수를 세어 /root/hdp/small/har_files.txt 에 정수로 적으세요.har://경로로raw/sensor-0042.csv를 읽어 로컬 /root/hdp/small/sensor-0042.csv 에 저장하세요.- raw 와 raw.har 의 NameNode 객체 수(파일 + 디렉터리 + 블록)를 /root/hdp/small/compare.json 에
{"raw_objects": 정수, "har_objects": 정수}로 쓰세요. hadoop distcp -D mapreduce.framework.name=local /user/root/small/archive /user/root/backup/small-archive로 아카이브를 복사하세요.- /root/hdp/small/report.md 에
## NameNode 가 치르는 값## HAR## 옮기기세 절을 쓰세요. 첫 절에 6단계의raw_objects를, 둘째 절에har_objects를 넣으세요.
참고
- 파일·디렉터리 수:
hdfs dfs -count <경로>(또는 WebHDFSGETCONTENTSUMMARY), 블록 수:hdfs fsck <경로>요약의Total blocks (validated). - HAR 의 안:
_index(파일마다 한 줄 — 경로, 종류, 어느 part 의 어디서부터 몇 바이트),_masterindex(색인의 색인),part-0(내용을 이어 붙인 것).hdfs dfs -cat /user/root/small/archive/raw.har/_index | head로 보세요. -r 1은 아카이브 파일의 복제 계수입니다(기본 3 — DataNode 가 하나라 복제 부족이 됩니다).- 흔한 실수:
har://경로에 아카이브 이름을 빼는 것,-p로 준 부모 기준의 상대 경로(raw)를 절대 경로로 쓰는 것, 디렉터리 줄까지 파일 수에 넣는 것. - 공식 문서: Hadoop Archives Guide · DistCp Guide · HDFS Architecture · FileSystem Shell — count
작은 파일 2,000개 올리기
/data/small 을 HDFS /user/root/small/raw 로 올리세요. hdfs dfs -put -t 8 /data/small /user/root/small/raw 처럼 여러 줄기로 올리면 빠릅니다.
한 줄기로 올리면 파일마다 NameNode 와 몇 번씩 주고받아서 2,000개에 10분이 넘게 걸립니다. 작은 파일은 크기가 아니라 개수로 비용을 치릅니다 — 이것부터가 작은 파일 문제입니다.
NameNode 가 들고 있는 객체 세기
hdfs dfs -count 와 hdfs fsck 로 /user/root/small/raw 의 파일 수·디렉터리 수·블록 수를 구해 /root/hdp/small/objects.json 에 {"raw_files": 정수, "raw_dirs": 정수, "raw_blocks": 정수} 로 쓰세요.
파일 하나에 블록 하나(파일이 블록 크기보다 작으니까), 거기에 디렉터리 하나. NameNode 힙에서는 이 셋이 모두 객체입니다. 블록 크기가 128MB 여도 수백 바이트짜리 파일의 블록이 128MB 를 차지하지는 않지만, 객체는 똑같이 하나를 차지합니다.
아카이브로 묶기
hadoop archive -D mapreduce.framework.name=local -archiveName raw.har -p /user/root/small -r 1 raw /user/root/small/archive 로 /user/root/small/archive/raw.har 를 만드세요.
아카이브는 맵리듀스 잡입니다. 입력 파일 목록을 나눠 내용을 part-* 로 이어 붙이고, 파일마다 어디에 들어갔는지를 _index 에 적습니다. -D mapreduce.framework.name=local 은 YARN 없이 지금 JVM 안에서 돌리라는 뜻입니다. 원본(raw)은 그대로 남습니다.
har:// 로 안을 보기
hdfs dfs -ls -R har:///user/root/small/archive/raw.har 출력에서 파일(권한이 - 로 시작하는 줄)의 수를 세어 /root/hdp/small/har_files.txt 에 정수로 적으세요.
har:// 파일 시스템은 _index 를 읽어 원래의 디렉터리 트리를 보여 줍니다. NameNode 는 이 2,000개를 모릅니다 — 아카이브 안의 파일은 NameNode 의 객체가 아니라 색인의 줄입니다.
아카이브 안의 파일 하나 읽기
hdfs dfs -cat har:///user/root/small/archive/raw.har/raw/sensor-0042.csv 로 읽은 내용을 로컬 /root/hdp/small/sensor-0042.csv 에 저장하세요.
경로는 har://<아카이브 경로>/<-p 기준 상대 경로> 입니다. har 파일 시스템은 _masterindex·_index 로 part 파일 안의 위치를 찾아 그 바이트만 읽습니다. 원본 /data/small/sensor-0042.csv 와 cmp 로 견줘 보세요.
객체 수를 견주기
raw 와 raw.har 각각의 NameNode 객체 수(파일 수 + 디렉터리 수 + 블록 수)를 구해 /root/hdp/small/compare.json 에 {"raw_objects": 정수, "har_objects": 정수} 로 쓰세요.
raw 는 파일 2,000 + 디렉터리 1 + 블록 2,000 입니다. raw.har 는 디렉터리 하나와 파일 몇 개(_index·_masterindex·part-0·_SUCCESS)와 그 블록뿐입니다. 몇 분의 일로 줄었는지 계산해 보세요.
distcp 로 통째로 옮기기
hadoop distcp -D mapreduce.framework.name=local /user/root/small/archive /user/root/backup/small-archive 로 아카이브를 복사하세요. 복사본의 raw.har 안 파일들이 원본과 같은 길이여야 합니다.
distcp 는 파일 목록을 나눠 여러 맵이 병렬로 복사하는 맵리듀스 잡입니다. 클러스터 사이 이전·백업에 쓰는 표준 도구이고, 작은 파일을 묶어 두면 복사할 파일 수가 줄어 이것도 빨라집니다. 대상 경로가 없으면 원본 디렉터리의 내용이 그 이름으로 복사됩니다.
작은 파일의 값을 숫자로
/root/hdp/small/report.md 에 ## NameNode 가 치르는 값 ## HAR ## 옮기기 세 절을 쓰세요. 첫 절에 6단계의 raw_objects 를, 둘째 절에 har_objects 를 숫자로 넣으세요.
NameNode 힙이 무엇을 세는지, HAR 이 무엇을 줄이고 무엇을 포기하는지(읽기 전용), 작은 파일이 애초에 생기지 않게 하려면 쓰는 쪽에서 무엇을 해야 하는지를 적으세요.