LabHub
배우기 러닝패스 코스

Apache Hadoop — Stand up and run HDFS and YARN in one pod

Bundle 2,000 small files into an archive and measure NameNode object counts

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

센서 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 없이 로컬 실행기로 돌린다. 둘 다 맵리듀스 잡이지만 실행 위치는 설정 하나로 바뀐다 — 같은 잡이 노트북에서도 클러스터에서도 돈다.

단계

  1. /data/small 디렉터리(파일 2,000개)를 HDFS /user/root/small/raw 로 올리세요(hdfs dfs -put -t 8 로 여러 줄기로 올리면 빠릅니다).
  2. raw 의 파일 수·디렉터리 수·블록 수를 /root/hdp/small/objects.json{"raw_files": 정수, "raw_dirs": 정수, "raw_blocks": 정수} 로 쓰세요.
  3. hadoop archive -D mapreduce.framework.name=local -archiveName raw.har -p /user/root/small -r 1 raw /user/root/small/archive 로 아카이브를 만드세요.
  4. hdfs dfs -ls -R har:///user/root/small/archive/raw.har 로 아카이브 안의 파일 수를 세어 /root/hdp/small/har_files.txt 에 정수로 적으세요.
  5. har:// 경로로 raw/sensor-0042.csv 를 읽어 로컬 /root/hdp/small/sensor-0042.csv 에 저장하세요.
  6. raw 와 raw.har 의 NameNode 객체 수(파일 + 디렉터리 + 블록)를 /root/hdp/small/compare.json{"raw_objects": 정수, "har_objects": 정수} 로 쓰세요.
  7. hadoop distcp -D mapreduce.framework.name=local /user/root/small/archive /user/root/backup/small-archive 로 아카이브를 복사하세요.
  8. /root/hdp/small/report.md## NameNode 가 치르는 값 ## HAR ## 옮기기 세 절을 쓰세요. 첫 절에 6단계의 raw_objects 를, 둘째 절에 har_objects 를 넣으세요.

참고

작은 파일 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 -counthdfs 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.csvcmp 로 견줘 보세요.

객체 수를 견주기

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 이 무엇을 줄이고 무엇을 포기하는지(읽기 전용), 작은 파일이 애초에 생기지 않게 하려면 쓰는 쪽에서 무엇을 해야 하는지를 적으세요.