
[ "하둡 완벽 가이드 4판" ] 공부한 후 정리한 내용 입니다
3. 하둡 분산 파일 시스템
분산 파일 시스템 : 네트워크로 연결된 여러 머신의 스토리지를 관리하는 파일 시스템
1) HDFS 설계
하둡은 HDFS 라는 분산 파일 시스템을 사용
→ 대용량 파일을 여러 서버에 나눠 저장하고, 빠르게 순차 읽기가 가능하도록 설계됨.
- HDFS가 잘 맞지 않는 응용 분야
- 빠른 응답 시간 요구
→ HDFS는 처리량(Throughput)에 최적화. (실시간 응답은 HBase가 대안) - 수많은 작은 파일
→ 네임노드 메모리에 파일 메타데이터를 저장해야 하므로 파일이 많아지면 메모리 부담이 큼. - 다중 라이터, 임의 수정 불가
→ 기본적으로 한 번 쓰거나, 파일 끝에 Append만 가능.
→ Hadoop 3.0부터 다중 라이터 일부 지원.
단일 라이터 : 한 파일에 한 번에 한 사람만 쓰기 가능
다중 라이터 : 한 파일에 여러 사람이 동시에 쓰기 가능
2) HDFS 개념
2.1 블록
- HDFS에서 데이터를 저장하는 최소 단위 (기본 128MB).
- 파일은 여러 블록으로 쪼개져 분산 저장됨.
특징
- 작은 파일도 크기만큼만 저장 → 공간 낭비 없음.
- 블록 단위 저장 덕분에 → 내고장성, 가용성, 확장성 제공.
- HDFS 블록이 큰 이유 : 탐색 비용 최소화 ( 탐색을 줄이고 데이터 전송에 더 많은 시간 할애 가능 )
이점
- 단일 디스크 크기보다 큰 파일 저장 가능.
- 블록 단위 추상화로 스토리지 구조 단순화.
- 블록 복제(Replication)로 장애 대응.
블록 상태 확인 명령
hdfs fsck / -files -blocks
내고장성 : 일부 디스크 고장시 데이터 손실 없이 계속 사용
가용성 : 데이터가 항상 접근 가능하도록 복제/분산되 있어 읽기, 쓰기 서비스가 중단되지 않음
2.2 네임노드 & 데이터 노드
- hdfs 기본 구성 : 네임노드 2, 데이터 노드 n
네임노드 (관리자)
- 파일 시스템 네임스페이스 관리 (메타데이터 저장), 네임스페이스 이미지, edit 로그 두 종류 파일 네임노드 로컬 디스크 영속 저장
- 네임스페이스 이미지 ( HDFS 전체 스냅샷 ), edit 로그 ( fsimage 이후 발생한 모든 변경 기록 ) >> 주기적 병합
- "어떤 파일이 어떤 블록으로 나뉘어, 어느 데이터노드에 있는지" 추적.
- 장애 시 HDFS 전체가 멈춤 ( 데이터 노드에 실질적 블록이 있지만 블록 정보만으로 파일 재구성을 할수 없음.. ) → 장애 복구 필수
데이터노드 (일꾼)
- 실제 블록을 저장하고 요청 시 제공.
- 블록 목록을 네임노드에 주기적으로 보고.
hdfs 클라이언트
- 사용자는 open(), read(), write()만 호출하면 됨.
- 블록 위치, 복제, 네트워크 전송은 클라이언트가 자동 처리.
- 즉, 사용자는 복잡한 HDFS 내부 구조 몰라도 코드 작성 가능
2.3 블록 캐싱
- HDFS에서 자주 읽는 블록을 데이터노드 메모리에 올려두는 기능입니다.
- 보통은 블록을 디스크에서 읽는데, 캐싱하면 메모리에서 즉시 읽기 가능 → 훨씬 빠름.
특징
- 단위: 블록 단위로 캐싱되지만, 사용자는 파일 단위로 캐시 설정 가능.
- 위치: 블록은 한 데이터노드 메모리에만 올라감. (2, 3 복제본 블록 캐싱 안함, 모든 노드에 올려두는 게 아님)
- 관리: HDFS가 어떤 블록이 캐시되었는지 정보를 유지.
동작 방식
- 사용자가 특정 파일을 캐시하도록 지시(명령)함.
- 데이터노드가 해당 블록을 메모리에 적재.
- 클라이언트가 파일 읽기 요청 시:
- HDFS는 "이 블록이 캐시되었는지" 확인.
- 캐시된 경우 → 메모리에서 읽음 (빠름).
- 없는 경우 → 디스크에서 읽음 (느림).
- Spark/MapReduce 잡 스케줄러는 캐시된 블록이 있는 데이터노드에서 우선 작업 실행 → 데이터노드 메모리에서 읽어 디스크 I/O 부하를 줄임
장점
- 반복해서 접근하는 데이터 읽기 성능을 크게 향상.
- 데이터 노드 메모리에서 읽으므로 디스크 I/O 감소 ( 디스크 seek + read 시간 사라 )
- 특히, 반복적 쿼리/잡에 유리.
활용 사례 ( 작은 Lookup 테이블 캐싱 )
- 예: SQL 조인 시, 큰 테이블 A와 작은 테이블 B가 있을 때
- 작은 테이블 B를 블록 캐시에 올려두면 → 디스크 대신 메모리에서 바로 읽음.
- → 반복적으로 조인해도 속도 훨씬 빨라짐.
캐시 지시자
- 특정 파일이나 디렉터리를 캐시 대상으로 지정.
- HDFS는 해당 파일의 블록을 데이터노드 메모리에 유지.
[ 명령어 예시 ]
hdfs cacheadmin -addDirective -path /user/data/small_table -pool pool1
→ /user/data/small_table 파일을 pool1 캐시 풀에 등록.
캐시 풀
- 캐시 리소스를 관리하는 그룹 단위 관리 시스템.
- 여러 사용자/잡이 캐시를 공유하거나 접근 권한 제어 가능.
- 관리자 입장에서, "누가 어떤 파일을 캐시할 수 있는지" 통제할 수 있음.
2.4 HDFS 페더레이션
- 하나의 네임노드가 모든 메타데이터를 관리하면 병목이 생기므로, 여러 네임노드가 서로 다른 네임스페이스(파일 시스템 영역) 를 나눠서 관리하는 구조. → 확장성과 성능 향상.
- 예시
- NameNode A → /user 디렉터리 관리
- NameNode B → /share 디렉터리 관리
구성 요소
- 네임스페이스 볼륨: 각 네임노드가 관리하는 메타데이터 공간. 서로 독립적.
- 블록 풀: 실제 파일 데이터를 담는 블록 집합. 데이터노드가 여러 블록 풀을 동시에 관리. → 네임스페이스와는 독립적이지 않음
데이터 노드 등록
- 모든 데이터노드는 클러스터 내 모든 네임노드에 등록.
- 따라서 하나의 데이터노드가 여러 네임스페이스의 블록을 저장할 수 있어, 데이터 분산 + 확장성이 좋아짐.
정리 : 여러 네임노드가 영역별로 관리 / 데이터노드는 모든 블록 저장 → 확장성과 성능 최적화.
2.5 HDFS 고가용성 ( HA )
- Hadoop 2.x부터 지원.
- 기존 단일 네임노드 구조의 단점을 해결 → 장애 시 자동 복구 가능.
HA를 위한 구조 변경
- 네임노드 공유 스토리지
- EditLog를 공유 저장소(저널노드)에 기록.
- Active와 Standby가 동일한 상태 유지.
- 데이터노드 블록 리포트
- 두 네임노드 모두에게 블록 정보를 보고.
- 클라이언트 로직 개선
- Active/Standby 전환 시 자동으로 올바른 네임노드로 요청.
- Standby 작업
- 스탠바이 네임노드는 주기적으로 네임스페이스 체크포인트 생성 → 장애 대비.
QJM ( Quorum Journal Manager )
- HA 전용 공유 스토리지 방식.
- 저널노드(JournalNode) 그룹에 EditLog를 동시에 기록.
- 과반수 노드에 기록 성공해야 유효.
- 안정성과 일관성 확보.
저널 노드( JournalNode )
- 공유 저널 스토리지 역할.
- 최소 3대 이상 구성 권장 (Quorum 구조).
- Active NN이 기록하면 Standby NN도 같은 로그를 읽어 동기화.
장애 복구
- Failover Controller
- 각 NN마다 동작하며 하트비트로 상태 감시.
- Active 장애 시 Standby를 Active로 승격.
- 펜싱(Fencing)
- 장애 난 기존 Active가 다시 영향력을 행사하지 못하도록 강제로 종료.
- 방법 예시: SSH 접속 후 프로세스 kill.
정리: Active-Standby 구조 + QJM + Failover Controller + Fencing 으로 네임노드 장애 시 서비스 중단 없이 자동 복구.
3) 명령행 인터페이스
3.1 핵심 설정
1. 기본 파일 시스템 (fs.defaultFS) → 기본 HDFS 주소 설정
- 기본값: hdfs://localhost/ ( ex.. 예시 hdfs://sycluster )
- 역할:
- HDFS 데몬 → 네임노드 호스트와 포트 결정
- HDFS 클라이언트 → 네임노드 주소 확인
2. 레플리카 설정 (dfs.replication)
- 기본값: 3
- 파일 저장 시 복제본(레플리카) 개수를 의미
3.2 자주 쓰는 명령어
1. 로컬 → HDFS 업로드
hadoop fs -copyFromLocal /sy0218/sy.txt /user/sy/sy.txt
2. HDFS → 로컬
hadoop fs -copyToLocal /user/sy/sy.txt sy.copy.txt
4) 하둡 파일 시스템
- 하둡은 여러 종류의 파일 시스템을 통합적으로 다룰 수 있는 "추상화 인터페이스" 제공
- 즉, hdfs, 로컬, 클라우드 스토리지도 동일한 방식으로 접근 가능!!
4.1 기본 개념
- org.apache.hadoop.fs.FileSystem: 하둡 파일 시스템 접근을 위한 클라이언트 인터페이스
- URL 스킴을 통해 어떤 파일시스템 쓸지 선택
# 로컬
hadoop fs -ls files:///
# 하둡 분산 파일 시스템
hadoop fs -ls hdfs:///
# Aws s3
hadoop fs -ls s3a://[ 버킷 명 ]/
4.2 주요 파일 시스템 구현체
| [ 스킴 ] | [ 클래스 ] | [ 설명 ] |
| file | fs.LocalFileSystem | 로컬 디스크용, 체크섬 사용 |
| hdfs | hdfs.DistributedFileSystem | 하둡 분산 파일 시스템 |
| webhdfs | hdfs.web.WebHdfsFileSystem | HTTP 기반 HDFS 접근 |
| har | fs.HarFileSystem | 아카이브(HAR) 파일 지원 |
| viewfs | viewfs.ViewFileSystem | 페더레이션 네임노드 마운트 시 사용 |
| ftp | fs.ftp.FTPFileSystem | FTP 서버 연결 |
| s3a | AWS S3 | 아마존 S3 지원 |
| wasb | Azure Storage | 마이크로소프트 Azure 지원 |
| swift | OpenStack Swift | 오픈스택 Swift 지원 |
4.3 하둡 파일 시스템 인터페이스 ( Java API vs WebHDFS )
1. java API
- 프로토콜: 하둡 내부 바이너리 프로토콜(RPC) + 내부 직렬화 사용
- 연결 방식: 네임노드와 통신 후 데이터노드와 직접 연결
- 성능: 빠름 → 대용량 파일 처리에 유리
2. WebHDFS
- 프로토콜: HTTP + REST 기반
- 연결 방식:
- 클라이언트 → 네임노드 요청
- 네임노드 → 데이터노드 위치 전달
- 클라이언트 → 데이터노드 요청 → 파일 전송
- 성능: 느림 → HTTP 통신 오버헤드와 리디렉션 단계 때문
3. WebHDFS 느린 이유!!
- HTTP 통신 오버헤드
- REST API 방식으로, 요청마다 HTTP 헤더와 메타데이터 전송/파싱 필요
- JSON, XML 응답 처리 때문에 추가 리소스 사용
- 2단계 리디렉션 구조
- 네임노드 → 데이터노드 위치 → 데이터 전송
- 데이터 전송 효율
- Java API: DFSClient 통해 소켓 기반 고속 전송 → 하둡 내부 바이너리 직렬화 사용 → 패킷 크기 최소화
- WebHDFS: HTTP 스트리밍 사용 → 낮은 전송 효율, 리소스 추가 사용 → 텍스트 헤더 + URL + 상태 코드 포함 → 동일 데이터라도 더 많은 바이트 전송
정리: 대용량 파일 전송이나 성능이 중요한 작업에는 Java API가 유리
- RPC = 바이너리 + 최소 메시지 + 스트리밍 최적화 → 빠름
- HTTP = 텍스트 + 헤더/리디렉션 + REST 호출 → 느림
5) 자바 인터페이스 ( 하둡 파일 시스템 )
1. FileSystem ( 추상 클래스 )
- 무엇?
하둡에서 파일을 읽고 쓰고 삭제하는 등 공통 작업을 정의한 기본 틀(인터페이스) - 주요 기능:
- open() : 파일 읽기
- create() : 파일 생성
- delete() : 파일 삭제
- listFiles() : 파일 목록 조회
- 특징:
- HDFS 뿐만 아니라 로컬, S3, Azure 등 다양한 저장소와 호환 가능
- 코드가 특정 저장소에 종속되지 않도록 도와줌
2. DistributedFileSystem ( HDFS 구현체 )
- 무엇?
FileSystem을 상속받아 HDFS 전용으로 동작하도록 만든 구현체 - 동작 방식:
- 네임노드(NameNode)와 데이터노드(DataNode)와 직접 통신
- HDFS 파일 읽기/쓰기/삭제 수행
3. Why?? FileSystem을 기준으로 코드 작성해야됨??
- 만약 코드에서 DistributedFileSystem만 사용하면 → 나중에 다른 저장소(S3, 로컬 등)로 바꾸기 어려움
- FileSystem 기준으로 코드를 작성하면 → 설정만 바꿔도 HDFS ↔ S3 ↔ 로컬 등 호환성 유지 가능
5.1 하둡 URL로 데이터 읽기
import java.io.InputStream;
import java.net.URL;
import org.apache.hadoop.fs.FsUrlStreamHandlerFactory;
import org.apache.hadoop.io.IOUtils;
public class URLCat {
// 프로그램 시작 시 단 한 번 실행되는 static 블록
static {
// 하둡 파일 시스템 URL 스킴 등록
// "hdfs://", "file://", "s3a://" 등을 URL로 읽을 수 있게 함
URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
}
public static void main(String[] args) throws Exception {
InputStream in = null; // 파일 입력 스트림 변수
try {
// args[0] : 실행 시 전달된 URL (예: hdfs://localhost:8020/user/file.txt)
// URL 객체 생성 → 지정한 파일 위치를 가리킴
in = new URL(args[0]).openStream(); // 파일 읽기 스트림 열기
// 파일 내용을 콘솔(System.out)으로 출력
// 4096 바이트 버퍼 사용, false → 스트림 닫지 않음
IOUtils.copyBytes(in, System.out, 4096, false);
} finally {
// 입력 스트림을 안전하게 닫음 → 메모리 누수 방지
IOUtils.closeStream(in);
}
}
}
--- 실행 예시 ---
export HADOOP_CLASSPATH=hadoop-examples.jar
hadoop URLCat hdfs://localhost/user/sy/sy.txt
--- 출력 결과 ---
세용용세용
바보보바보
5.2 파일 시스템 API로 데이터 읽기
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import java.io.InputStream;
import java.net.URI;
public class FileSystemCat {
public static void main(String[] args) throws Exception {
// 실행 시 첫 번째 인자로 파일 경로를 받음
// 예: hdfs://localhost:8020/user/sy/sy.txt
String uri = args[0];
// Hadoop 설정 객체 생성
Configuration conf = new Configuration();
// FileSystem 객체 생성
// URI와 conf를 기반으로 HDFS, 로컬, S3 등 알맞은 구현체 반환
FileSystem fs = FileSystem.get(URI.create(uri), conf);
InputStream in = null;
try {
// Path 객체로 파일 열기
// HDFS, 로컬 등 지정된 경로의 파일 읽기
in = fs.open(new Path(uri));
// 파일 내용을 콘솔(System.out)으로 출력
// 4096 바이트 버퍼 사용
// false → 스트림 자동 닫지 않음
IOUtils.copyBytes(in, System.out, 4096, false);
} finally {
// 입력 스트림 안전하게 닫기 → 메모리 누수 방지
IOUtils.closeStream(in);
}
}
}
--- 실행 예시 ---
hadoop FileSystemCat hdfs://localhost/user/sy/sy.txt
--- 출력 결과 ---
바보보
세이용
5.3 데이터 쓰기
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.util.Progressable;
import java.io.*;
public class FileCopyWithProgress {
public static void main(String[] args) throws Exception {
// -------------------------
// 1. 입력값 처리
// args[0] : 로컬 파일 경로
// args[1] : HDFS 목적지 경로
// -------------------------
if (args.length != 2) {
System.out.println("사용법: hadoop FileCopyWithProgress <local_src> <hdfs_dst>");
return;
}
String localSrc = args[0]; // 로컬 파일 경로
String dst = args[1]; // HDFS 목적지 경로
// -------------------------
// 2. 로컬 파일 입력 스트림 생성 (버퍼 적용)
// -------------------------
InputStream in = new BufferedInputStream(new FileInputStream(localSrc));
// -------------------------
// 3. Hadoop 설정 객체 생성
// -------------------------
Configuration conf = new Configuration();
// -------------------------
// 4. HDFS 파일시스템 객체 생성
// -------------------------
FileSystem fs = FileSystem.get(new java.net.URI(dst), conf);
// -------------------------
// 5. 출력 스트림 생성 + Progressable 구현
// → 복사 진행 시 "." 출력
// -------------------------
OutputStream out = fs.create(new Path(dst), new Progressable() {
public void progress() {
System.out.print("."); // 복사 중 진행 표시
}
});
// -------------------------
// 6. 파일 복사
// - 버퍼 크기: 4096 바이트
// - 마지막 true: 스트림 자동 닫기
// -------------------------
IOUtils.copyBytes(in, out, 4096, true);
System.out.println("\n파일 복사 완료: " + dst);
}
}
- HDFS는 대용량 데이터를 안정적으로 쓰기 위한 구조 때문에, 중간 수정과 무작위 쓰기를 지원하지 않고, 순차적 쓰기와 append만 가능!!
5.4 디렉터리
FileSystem fs = FileSystem.get(conf);
fs.mkdirs(new Path("/user/hadoop/mydir"));
- mkdirs(Path f) : 디렉터리를 생성하는 메서드
- 특징: 부모 디렉터리가 없어도 자동 생성
5.5 파일 시스템 질의
- 파일 메타 데이터 : FileStatus
>> 하둡 파일 시스템 파일 상태를 확인 하고 싶을떄 사용
- HDFS 파일이나 디렉터리의 메타데이터 조회 가능
- FileStatus 클래스 주요 정보:
- 파일 길이 (Size)
- 블록 크기 (Block size)
- 복제 수 (Replication)
- 수정 시간 (Modification time)
- 소유자/그룹, 권한 정보
FileStatus status = fs.getFileStatus(new Path("/user/hadoop/myfile.txt"));
System.out.println("파일 크기: " + status.getLen());
System.out.println("복제 수: " + status.getReplication());
5.6 데이터 삭제
public boolean delete(Path f, boolean recursive) throws IOException
- 반환값: boolean → 삭제 성공 시 true, 실패 시 false
- 파라미터
- Path f : 삭제할 파일 또는 디렉터리 경로
- boolean recursive : 디렉터리 안 내용까지 삭제할지 여부
- 예외 처리: IOException → 파일시스템 접근 실패, 권한 문제 등..
6) 데이터 흐름
- 하둡 파일 시스템에서 파일 읽고 쓰는 과정은 "클라이언트 → 네임노드 → 데이터노드"가 서로 협력해 진행
6.1 파일 읽기 ( FSDataInputStream )

1단계: 파일 열기
- 클라이언트는 DistributedFileSystem.open() 호출
- 파일 열기 → FSDataInputStream 반환
- FSDataInputStream: 사용자 입장에서 read()만 호출하면 데이터 읽기 가능
- 내부적으로 DFSInputStream이 실제 네임노드/데이터노드와 통신
2단계: 블록 위치 조회
- HDFS 파일은 블록(Block) 단위로 나눠 저장됨 (보통 128MB 또는 256MB)
- 클라이언트 → 네임노드 RPC 호출
- 네임노드 → 각 블록 위치와 복제본 데이터노드 목록 전달
- 클라이언트는 가까운 데이터노드부터 순서대로 연결
- 클라이언트가 데이터노드가 위치한 서버라면 로컬에서 바로 읽음 → 속도 향상
3단계: 데이터 읽기
- FSDataInputStream → DFSInputStream을 사용
- DFSInputStream → 블록 단위로 데이터노드와 연결, I/O 처리
- 클라이언트는 read() 반복 호출 → 데이터를 스트림처럼 전송 받음
- 블록 끝 도달 → DFSInputStream 연결 종료, 다음 블록 데이터노드 조회 → 연결 반복
읽는 도중 장애 처리
- 데이터노드 장애 발생 → 다른 블록 복제본과 연결
- 전송 중 데이터 체크섬 검증 → 체크섬 손상 시 다른 복제본에서 읽음
- 손상 블록 정보 → 네임노드에 동기화 → 차후 복제 생성
읽기 과정 핵심 포인트
- 클라이언트가 직접 데이터노드와 통신 → 트래픽 분산
- 네임노드: 메타데이터 관리만 → 데이터 전송 X, 병목 최소화
- 장애 대응 → 블록 복제본 활용
- 동시에 여러 클라이언트 읽기 가능
6.2 파일 쓰기 ( FSDataOutputStream )

1단계: 파일 생성
- 클라이언트 → DistributedFileSystem.create() 호출
- 네임노드 → 동일 파일 존재 여부, 권한 확인
- 실패 시 → IOException 발생
- 성공 시 → FSDataOutputStream 반환 (내부적으로 DFSOutputStream 사용)
2단계: 데이터 쓰기
- DFSOutputStream → 데이터를 작은 패킷으로 나눠 Data Queue에 저장
- DataStreamer → 패킷을 가져와 파이프라인 구성 후 데이터노드로 전송
- 파이프라인: 첫 번째 → 두 번째 → 세 번째 데이터노드 순서로 전송
- ACK 큐 관리: 각 패킷이 모든 데이터노드에서 승인 받아야 ACK Queue에서 제거
장애 처리
- 파이프라인 실패 → ACK 큐 패킷을 Data Queue 앞쪽으로 되돌려 재전송
- 정상 데이터노드는 새로운 블록 ID 받아 전송 재개
- 장애 데이터노드는 재기동 시 불완전 블록 삭제
- 네임노드는 불완전 블록 인식 → 차후 복제본 생성
- 최소 복제 수(dfs.namenode.replication.min) 이상 블록 전송 완료 시 → 쓰기 성공
3단계: 파일 닫기
- 클라이언트 → FSDataOutputStream.close() 호출
- 파이프라인에 남아 있는 모든 패킷 flush + ACK 대기
- 최종 전송 완료 후 → 네임노드에 파일 완료 신호 전달
- 네임노드 → 블록 복제 완료 확인 후 최종 성공 반환
쓰기 과정 핵심 포인트
- 한 파일 = 단일 writer
- DFSOutputStream + DataStreamer → 블록 단위 전송
- 장애 복구 → 실패 블록 재전송, 불완전 블록 삭제, 네임노드가 복제 처리
- close() → 모든 패킷 flush + 최종 블록 복제 확인
6.3 일관성 모델
- 파일 시스템 일관성 모델 : 파일에 데이터 쓸 떄, 언제&어떤 순서로 보이는가를 정한 규칙
- POSIX(리눅스/유닉스 표준)
- 데이터를 쓰자마자 다른 프로세스에서 읽을 수 있음
- close() 전에 이미 쓴 부분도 읽기 가능
HDFS는 왜 다를까?
- 목적: 대용량 데이터 분산 저장
- POSIX 처럼 즉시 읽기 가능하게 하면 성능이 크게 떨어짐
- 그래서 “쓰기 완료 후 일관성” 모델 채택 → 완전히 쓰여야 다른 클라이언트가 볼 수 있음
HDFS의 일관성 동작 예시
1. 파일 생성
- 네임노드에서 파일 존재는 바로 확인 가능
- 하지만 내용은 아직 없음
2. 데이터 쓰기 진행 중
- 파일이 여러 블록으로 나뉘어 기록됨
- 이미 기록이 끝난 블록은 다른 리더가 읽을 수 있음
- 현재 쓰고 있는 블록은 아직 읽을 수 없음
→ 즉, 블록 단위로 가시성이 생김!!
예시: 파일이 3블록
블록1 기록 완료 → 리더 읽기 가능
블록2 기록 중 → 리더는 블록2 읽을 수 없음
블록3 기록 전 → 리더는 아직 블록3 없음
3. 파일 닫기 (close())
- HDFS 내부적으로 hflush() 자동 실행
- 기록 완료된 블록은 모두 읽기 가능
4. close() 호출 후
- 내부적으로 hflush() + hsync() 보장
- 네임노드가 파일을 COMPLETE 상태로 마킹 ( 모든 블록 읽기 가능 + 정상 파일로 취급 )
hflush() vs hsync()
| 기능 | 설명 | 특징 |
| hflush() | 데이터노드 메모리 버퍼까지 플러시 | 읽을 수 있음, 전원 다운 시 유실 가능 |
| hsync() | 데이터노드 디스크까지 동기화 | fsync()와 유사, 강력한 안전성, 성능 저하 |
- 파일 닫기(close()) = 암묵적 hflush() 실행
- 성능 vs 안전성의 트레이드오프 존재
설계 팁
- 중간중간 안전하게 저장하려면 적절히 hflush(), hsync() 호출
- 너무 자주 → 안전하지만 성능 ↓
- 너무 드물게 → 빠르지만 장애 시 데이터 손실 위험 ↑
- 최적 균형점 찾아 처리 속도와 안정성 조정
포인트
- HDFS는 블록 단위로 기록 완료 시점에 가시성을 제공
- 완전히 쓰기 완료해야 전체 파일을 읽는 것이 아니라
- 이미 쓰여진 블록은 읽을 수 있음 → 블록 단위 스트리밍 가능
가시성 : 쓴 데이터가 다른 애 눈에 언제보이지
트레이드오프 : 어떤 걸 얻으면 다른 걸 포기해야하는 관계 ( ex.. 지원이 초밥 사주기 - 사랑을 얻지만 지갑은 포기 ㅋㅋ )
7) distcp 를 사용한 HDFS 데이터 복사 & 클러스터 균형 관리
7.1 distcp란?
- 대량 데이터를 병렬로 HDFS에 복사하기 위한 도구
- 단순 hadoop fs -cp 대신 사용 → 대규모 파일/디렉터리 복사에 최적화
- 내부적으로 MapReduce 잡으로 실행 (리듀스 없음)
1. 파일/디렉터리 단순 복사
hadoop distcp file1 file2
2. 변경된 파일만 복사
hadoop distcp -update dir1 dir2
3. 클러스터 간 데이터 이동 + 삭제 옵션
## -delete : 타깃 경로에만 존재하는 파일 지우는 옵션
hadoop distcp -update -delete -p hdfs://namenode1/foo hdfs://namenode2/foo
4. 버전이 다른 클러스터 간 복사
## WebHDFS 사용
hadoop distcp webhdfs://namenode1:50070/foo webhdfs://namenode2:50070/foo
- 기본적으로 20개 맵이 사용되며 -m 옵션으로 조정 가능
7.2 HDFS 클러스터 균형 유지
- HDFS는 데이터를 여러 노드에 분산해야 성능과 안정성 유지
- 그런데 distcp로 맵을 1개만 사용(-m 1)하면:
- 첫 번째 복사본 블록이 특정 노드에 몰림 → 불균형 발생
해결 방법
- 맵(Map) 개수 늘리기
- 여러 노드에서 동시에 복사 수행 → 블록이 여러 노드에 퍼짐
- 균형 향상, 처리 속도 증가
- 단점: 너무 많이 늘리면 다른 잡(Job) 영향 있음
- HDFS Balancer 사용
- 클러스터 전체 스캔 후, 데이터가 몰린 노드에서 여유 노드로 블록 이동
- 점진적으로 균형 회복
- 단점: 시간이 걸림

1. HDFS 설계: 대용량 파일 분산 저장 + 순차 읽기 최적화.
2. 블록(Block): 저장 최소 단위 128MB, 복제 → 내고장성/가용성.
3. 네임노드: 메타데이터 관리, 장애 시 HDFS 전체 영향.
4. 데이터노드: 실제 블록 저장, 네임노드에 상태 보고.
5. 클라이언트: open/read/write만 호출 → 내부 처리 자동.
6. 블록 캐싱: 자주 쓰는 데이터 메모리 저장 → 읽기 성능 ↑.
7. HA 구조: Active/Standby + QJM → 네임노드 장애 자동 복구.
8. 쓰기 모델: 블록 단위, 단일 writer, close() 후 전체 파일 가시성.
9. 일관성: "쓰기 완료 후 읽기 가능" → 블록 단위 스트리밍 가능.
10. distcp: 대규모 HDFS 데이터 병렬 복사, 클러스터 균형 유지 가능.'데이터 엔지니어( 실습 정리 ) > hadoop' 카테고리의 다른 글
| 5. 하둡 I/O ( 하둡 기초 ) (0) | 2026.01.12 |
|---|---|
| 4. Yarn ( 하둡 기초 ) (0) | 2025.10.11 |
| 2. 맵 리듀스 ( 하둡 기초 ) (0) | 2025.09.06 |
| 1. 하둡과의 만남 ( 하둡 기초 ) (0) | 2025.09.02 |