LabHub
学习 学习路径 课程

Apache Hadoop — HDFS 와 YARN 을 한 파드에 세우고 운영한다 · NameNode 메타데이터 · 讲解

NameNode 는 기억을 fsimage 와 edits 두 곳에 나눠 적는다

在 LabHub 中继续学习

한 줄 요약

NameNode 는 이름공간 전체를 메모리에 들고 있고, 디스크에는 어느 시점의 사진(fsimage)그 뒤의 변경 일지(edits) 를 따로 적는다. 둘을 합치는 일이 체크포인트이고, 블록이 어느 DataNode 에 있는지는 어디에도 적지 않아서 기동할 때마다 안전 모드에서 보고를 기다린다.

概念图: 어느 시점의 사진(fsimage) · 그 뒤의 변경 일지(edits) · 안전 모드 · EditLog 라는 트랜잭션 일지

왜 파일 하나로 끝나지 않나

파일을 하나 만들 때마다 이름공간 전체를 디스크에 새로 쓰면 어떻게 될까. 파일이 천만 개인 클러스터에서 mkdir 한 번이 수 기가바이트짜리 쓰기가 된다. 반대로 변경만 이어 적고 전체 모습은 한 번도 저장하지 않으면, 재시작할 때 몇 달 치 일지를 처음부터 다시 돌려야 한다.

HDFS 는 두 방식을 섞었다. [HDFS 설계 문서](https://hadoop.apache.org/docs/r3.5.0/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html)는 NameNode 가 메타데이터의 모든 변경을 EditLog 라는 트랜잭션 일지에 적고, 블록과 파일의 대응과 파일 속성을 포함한 이름공간 전체는 FsImage 라는 파일에 담는다고 설명한다. 같은 문서는 이유도 짧게 적는다 — FsImage 를 읽는 것은 효율적이지만 FsImage 에 변경을 하나씩 반영하는 것은 효율적이지 않다. 그래서 변경은 일지 끝에 붙이기만 하고(순차 쓰기라 빠르다), 사진은 가끔 새로 찍는다.

이 구조를 모르면 두 가지 사고를 겪는다. 하나는 재시작이 한 시간씩 걸리는 사고다. [사용자 안내서](https://hadoop.apache.org/docs/r3.5.0/hadoop-project-dist/hadoop-hdfs/HdfsUserGuide.html)가 경고하듯 edits 가 커질수록 다음 재시작이 길어진다. 다른 하나는 NameNode 디렉터리를 잃는 사고다. 이 디렉터리가 곧 HDFS 의 전부다 — DataNode 에 블록 파일이 멀쩡히 남아 있어도 그것이 어느 파일의 몇 번째 조각인지 아는 곳은 여기뿐이다.

어떻게 동작하나

NameNode 저장 디렉터리의 current/ 를 열면 대략 이런 모양이다.

current/  VERSION  seen_txid  fsimage_0000000000000000000  fsimage_0000000000000000000.md5  edits_0000000000000000001-0000000000000000042  edits_inprogress_0000000000000000043

파일 이름의 숫자는 트랜잭션 번호(txid) 다. fsimage_N 은 N 번 트랜잭션까지 반영된 사진이고, edits_A-B 는 A 부터 B 까지의 닫힌 일지 조각, edits_inprogress_C 는 지금 쓰고 있는 조각이다. 기동할 때 NameNode 는 가장 최근 fsimage 를 메모리에 올리고, 그 번호 뒤의 edits 를 차례대로 다시 적용한다. 그러면 멈추기 직전의 이름공간이 메모리에 복원된다.

NameNode 디스크의 fsimage 와 edits 조각이 트랜잭션 번호로 이어지는 그림. 기동하면 fsimage 를 메모리에 올리고 뒤의 edits 를 차례로 적용해 이름공간을 복원한다. 체크포인트는 둘을 합쳐 새 fsimage 를 쓰고, 블록 위치는 디스크에 없어 DataNode 의 블록 보고로 채운다

체크포인트는 이 합치기를 미리 해 두는 일이다. 설계 문서에 따르면 체크포인트는 정해진 시간 간격(dfs.namenode.checkpoint.period)이나 쌓인 트랜잭션 수(dfs.namenode.checkpoint.txns) 중 먼저 닿는 쪽에서 일어난다. [hdfs-default.xml](https://hadoop.apache.org/docs/r3.5.0/hadoop-project-dist/hadoop-hdfs/hdfs-default.xml)의 기본값은 3600초와 1,000,000 트랜잭션이다. 이 합치기는 NameNode 자신이 아니라 보통 Secondary NameNode(HA 구성이면 Standby NameNode)가 한다. 이름 때문에 예비 NameNode 로 오해받지만, Secondary 는 장애가 나도 대신 서비스하지 않는다. 사진을 새로 찍어 돌려주는 조수일 뿐이다.

남는 사진 수도 정해져 있다. dfs.namenode.num.checkpoints.retained 의 기본은 2 이고, 가장 오래된 사진부터 지금까지를 복원하는 데 필요한 edits 는 함께 남긴다. 사진 하나가 깨져도 하나 전으로 돌아갈 길을 남겨 두는 것이다.

여기서 꼭 짚을 것이 있다. fsimage 에는 블록이 어느 DataNode 에 있는지가 없다. 파일이 어떤 블록 ID 들로 이뤄졌는지는 적혀 있지만, 그 블록의 복제본이 어느 서버의 어느 디스크에 있는지는 DataNode 가 기동하면서 보내는 블록 보고(Blockreport) 로 매번 새로 채운다. 위치는 디스크가 죽고 서버가 바뀌면서 계속 달라지기 때문에, 적어 두면 틀린 정보가 되기 쉽다.

안전 모드는 무엇을 기다리나

그래서 막 뜬 NameNode 는 이름은 다 알지만 블록이 어디 있는지는 모른다. 이 상태에서 복제본이 부족하다고 판단해 복제를 시작하면, 아직 보고를 안 한 DataNode 가 멀쩡히 들고 있는 블록까지 불필요하게 복제하게 된다. 설계 문서가 말하는 Safemode 는 이 오판을 막는 대기 상태다. [명령 참조](https://hadoop.apache.org/docs/r3.5.0/hadoop-project-dist/hadoop-hdfs/HDFSCommands.html)는 안전 모드의 NameNode 가 이름공간 변경을 받지 않고(읽기 전용) 블록을 복제하거나 지우지도 않는다고 정리한다.

빠져나가는 조건은 설정으로 정한다. dfs.namenode.safemode.threshold-pct 의 기본은 0.999f 이다. 블록의 99.9% 가 최소 복제 수만큼 보고되면 조건이 채워지고, 거기에 dfs.namenode.safemode.extension 기본 30000ms(30초)를 더 기다렸다가 나간다(노드가 하나뿐인 실습 이미지는 이 여유를 0 으로 두었다). 운영자가 hdfs dfsadmin -safemode enter 로 일부러 들어갈 수도 있다.

일부러 들어가는 대표적인 이유가 -saveNamespace 다. 명령 참조에 따르면 이 명령은 현재 이름공간을 저장 디렉터리에 새 fsimage 로 쓰고 edits 를 새로 시작하는데, 안전 모드가 필요하다. 사진을 찍는 동안 이름공간이 바뀌면 사진이 어느 txid 의 모습인지가 흐려지기 때문이다.

디스크를 열지 않고 읽는 법

fsimage 와 edits 는 바이너리라 cat 으로 읽을 수 없다. 대신 두 오프라인 도구가 있다. [오프라인 이미지 뷰어(oiv)](https://hadoop.apache.org/docs/r3.5.0/hadoop-project-dist/hadoop-hdfs/HdfsImageViewer.html)는 fsimage 를 사람이 읽는 형식으로 바꾸고, 클러스터가 떠 있지 않아도 된다. 기본 처리기는 읽기 전용 WebHDFS 를 띄우는 Web 이고, -p XML 은 모든 정보를 담은 가장 큰 출력을, -p Delimited 는 경로·복제 수·블록 크기·블록 수·파일 크기·쿼터·권한을 한 줄에 하나씩 구분자로 늘어놓은 출력을 낸다. 스크립트로 세고 거르기에는 Delimited 가 편하다.

[오프라인 일지 뷰어(oev)](https://hadoop.apache.org/docs/r3.5.0/hadoop-project-dist/hadoop-hdfs/HdfsEditsViewer.html)는 edits 조각을 읽는다. 기본 처리기가 xml 이라 RECORD 마다 OPCODE(OP_MKDIR, OP_ADD, OP_CLOSE, OP_DELETE 같은 것)와 TXID 가 보이고, -p stats 는 연산 코드별 개수만 세어 준다. 누가 언제 무엇을 지웠는지 감사할 때, 혹은 이름공간이 왜 갑자기 커졌는지 볼 때 쓰는 도구다.

현장에서 만나는 모습

첫째, 기본 저장 위치는 /tmp 아래다. dfs.namenode.name.dir 의 기본값은 file://${hadoop.tmp.dir}/dfs/name 이고 hadoop.tmp.dir/tmp/hadoop-${user.name} 이다. 설정 없이 띄운 NameNode 는 서버를 재부팅해 /tmp 가 비는 순간 이름공간을 통째로 잃는다. 운영에서는 이 값을 반드시 바꾸고, 쉼표로 여러 디렉터리를 주면 같은 내용이 모두에 복제된다.

둘째, 체크포인트가 멈춰도 한동안은 아무 증상이 없다. Secondary 가 죽어 있으면 edits 만 계속 길어지다가, 몇 주 뒤 재시작하는 날 NameNode 가 몇 시간째 일지를 다시 읽는다. 마지막 체크포인트 시각을 감시 항목에 넣어야 하는 이유다.

셋째, 안전 모드에서 안 나오면 블록 보고가 모자란 것이다. DataNode 가 덜 떴거나 디스크 하나를 잃어 99.9% 에 못 미치는 경우다. -safemode leave 로 억지로 나오기 전에 무엇이 빠졌는지부터 본다.

넷째, 사람 손으로 edits 를 고치는 날이 온다. 깨진 일지 끝부분 때문에 NameNode 가 뜨지 않으면 oev 로 XML 로 풀어 보고, 그 도구가 다시 바이너리로 되돌리는 길도 제공한다. 할 일이 없기를 바라지만 도구는 알아 둔다.

실무에서 진짜 중요한 것

다음 실습에서 할 것

한 파드에 뜬 NameNode 가 지금 안전 모드인지부터 확인하고, 안전 모드에 직접 들어가 디렉터리 만들기가 거절되는 것을 본다. 그 상태에서 saveNamespace 로 새 fsimage 를 만들어 파일 이름의 txid 를 읽은 뒤 안전 모드를 풀고 디렉터리를 하나 만든다. 이어서 oiv 로 그 fsimage 를 XML 과 구분자 형식으로 풀어 이름공간을 읽는다. 마지막으로 rollEdits 로 지금 쓰는 edits 구간을 닫고, 방금 한 디렉터리 만들기가 들어 있는 닫힌 구간을 oev 로 풀어 OP_MKDIR 기록이 몇 개인지 센다.