데이터 엔지니어 인터뷰 — Hadoop

HDFS

HDFS의 설계 전제는 무엇인가요

대용량 파일을 한 번 쓰고 여러 번 읽는(write-once, read-many) 패턴을 가정합니다. 그래서 임의 위치 수정이 안 되고, 순차 읽기 처리량에 최적화되어 있습니다.

또 하나의 전제는 하드웨어는 고장 난다는 것입니다. 값싼 장비를 여럿 쓰되 복제로 내구성을 확보하고, 장애를 예외가 아니라 정상 상황으로 다룹니다.

작은 파일이 많거나, 낮은 지연의 임의 접근이 필요하거나, 잦은 수정이 필요한 워크로드에는 맞지 않습니다.

블록 크기가 큰 이유는 무엇인가요

기본 128MB입니다. 일반 파일시스템(4KB)보다 훨씬 큰데, 이유는 탐색 시간 대비 전송 시간의 비율을 높이기 위해서입니다. 블록이 작으면 디스크 탐색 오버헤드가 전체 시간에서 차지하는 비중이 커집니다.

부수 효과로 NameNode의 메타데이터 부담도 줄어듭니다. 블록 개수가 적어지기 때문입니다.

NameNode와 DataNode의 역할을 설명해보세요

NameNode는 메타데이터를 관리합니다 — 디렉터리 구조, 파일과 블록의 매핑, 블록이 어느 DataNode에 있는지. 이 정보를 메모리에 올려두므로 NameNode 메모리가 클러스터가 담을 수 있는 파일 수의 상한이 됩니다.

DataNode는 실제 블록을 저장하고, 주기적으로 NameNode에 블록 리포트와 하트비트를 보냅니다.

블록 위치 정보는 디스크에 영속화하지 않습니다. DataNode들이 시작 시 보고하는 것으로 재구성합니다. 그래서 NameNode 재시작 후 안전 모드(safe mode)에서 보고를 기다립니다.

Secondary NameNode는 백업인가요

아닙니다. 이름 때문에 오해하기 쉬운데, 체크포인트 역할입니다.

NameNode는 변경 이력을 edits 로그에 append하고 전체 스냅샷은 fsimage에 둡니다. edits가 계속 커지면 재시작 시 재생 시간이 길어지므로, Secondary NameNode가 주기적으로 fsimage + edits를 병합해 새 fsimage를 만듭니다.

고가용성은 별도 기능입니다. Active/Standby NameNode를 두고 JournalNode로 edits를 공유하며, ZooKeeper 기반 자동 페일오버를 씁니다.

복제 정책은 어떻게 되나요

기본 복제 계수는 3이고, 배치 정책은 이렇습니다.

1번째 — 쓰기를 수행하는 노드(또는 임의 노드)
2번째 — 다른 랙의 노드
3번째 — 2번째와 같은 랙의 다른 노드

랙 하나가 통째로 죽어도 데이터가 살아남고, 동시에 모든 복제본을 다른 랙에 두는 것보다 네트워크 비용이 적습니다. 이 판단을 위해 rack awareness 설정이 필요합니다.

Erasure Coding은 무엇인가요

복제 대신 패리티로 내구성을 확보하는 방식입니다. 3배 복제는 저장 오버헤드가 200%인데, RS(6,3)은 50%로 비슷한 내구성을 얻습니다.

대신 복구 시 여러 노드에서 데이터를 읽어 계산해야 하므로 읽기·복구 비용이 큽니다. 자주 안 읽는 콜드 데이터에 적합합니다.

MapReduce

MapReduce의 처리 흐름을 설명해보세요

Input Split → Map → (Combine) → Partition → Shuffle & Sort → Reduce → Output

Map은 입력 스플릿마다 하나씩 실행되어 key-value를 내보내고, 파티셔너가 키를 기준으로 어느 Reducer로 보낼지 정합니다. Shuffle 단계에서 네트워크 전송과 정렬이 일어나고, Reducer는 같은 키의 값들을 모아 처리합니다.

Reducer 입력은 키로 정렬되어 있다는 점이 중요합니다. 정렬이 공짜로 되는 것이 아니라 Shuffle의 비용에 포함되어 있습니다.

Combiner는 무엇이고 언제 쓸 수 있나요

Map 쪽에서 미리 부분 집계를 해서 네트워크로 보내는 양을 줄이는 최적화입니다.

교환법칙과 결합법칙이 성립하는 연산에만 쓸 수 있습니다. sum, max, count는 되지만 average는 안 됩니다. 부분 평균의 평균은 전체 평균이 아니기 때문입니다. 평균이 필요하면 (합, 개수) 쌍을 내보내고 마지막에 나누면 됩니다.

Combiner는 실행이 보장되지 않습니다. 0번, 1번, 여러 번 실행될 수 있으므로 결과가 그에 무관해야 합니다.

데이터 지역성(data locality)은 무엇인가요

계산을 데이터가 있는 노드로 보내는 원칙입니다. 대용량에서는 데이터를 옮기는 비용이 코드를 옮기는 비용보다 훨씬 큽니다.

스케줄러는 node-local → rack-local → off-rack 순으로 배치를 시도합니다. 오브젝트 스토리지(S3, GCS)를 쓰는 요즘 구조에서는 지역성 개념이 사실상 사라졌고, 대신 네트워크 대역폭과 요청 병렬도가 중요해졌습니다.

Speculative execution은 무엇인가요

느린 태스크(straggler)를 감지해 같은 태스크를 다른 노드에서 중복 실행하고, 먼저 끝난 쪽을 채택하는 기능입니다.

하드웨어 문제로 느린 경우에는 도움이 되지만, 데이터 skew가 원인이면 소용이 없습니다. 복제본도 똑같이 많은 데이터를 처리해야 하므로 리소스만 낭비합니다.

YARN

YARN의 구성 요소를 설명해보세요

  • ResourceManager — 클러스터 전체 리소스를 관리하고 애플리케이션에 컨테이너를 할당
  • NodeManager — 각 노드에서 컨테이너를 실행하고 상태를 보고
  • ApplicationMaster — 애플리케이션마다 하나씩 뜨는 관리자. 필요한 컨테이너를 요청하고 태스크를 조율

핵심은 자원 관리와 잡 관리를 분리했다는 점입니다. 덕분에 MapReduce 외에 Spark, Flink 같은 다른 프레임워크도 같은 클러스터에서 돌 수 있게 됐습니다.

스케줄러 종류와 차이는 무엇인가요

스케줄러 특징
FIFO 먼저 온 잡이 자원을 다 씀. 큰 잡이 뒤를 막음
Capacity 큐별로 용량을 보장. 조직 단위 분리에 적합
Fair 실행 중인 잡들에 자원을 균등 배분

운영에서는 Capacity Scheduler로 팀·용도별 큐를 나누고, 큐마다 최소 보장과 최대 상한을 두는 구성이 흔합니다.

컨테이너 메모리 설정에서 자주 나는 문제는 무엇인가요

yarn.nodemanager.resource.memory-mb(노드가 제공하는 총량), yarn.scheduler.maximum-allocation-mb(컨테이너 하나의 최대), 그리고 애플리케이션이 요청하는 값이 어긋나는 경우입니다.

Spark에서는 spark.executor.memory 외에 spark.executor.memoryOverhead가 따로 붙어 실제 컨테이너 요청량이 됩니다. 힙은 여유 있는데 컨테이너가 YARN에 의해 kill되는 경우, 대개 오버헤드가 부족한 것입니다.

운영과 포맷

small files 문제는 왜 심각한가요

두 방향으로 문제가 됩니다.

NameNode 메모리 — 파일·블록마다 메타데이터가 메모리를 차지합니다. 1MB 파일 100만 개는 128MB 파일 8천 개보다 훨씬 많은 메모리를 씁니다.

태스크 오버헤드 — 스플릿이 파일 단위로 생기므로 작은 파일 100만 개는 태스크 100만 개가 됩니다. 태스크 시작 비용이 실제 처리 시간보다 커집니다.

대응은 적재 시점에 파일 크기를 맞추거나(compaction), CombineFileInputFormat으로 여러 파일을 한 스플릿에 묶거나, HAR·시퀀스 파일로 묶는 것입니다.

Parquet, ORC, Avro를 비교해보세요

포맷 구조 강점
Parquet 컬럼너 분석 쿼리. 컬럼 선택 읽기, 압축률
ORC 컬럼너 Parquet과 유사. Hive 계열에서 강함, 경량 인덱스
Avro 행 기반 전체 행을 읽고 쓰는 워크로드, 스키마 진화

분석용 테이블은 Parquet/ORC, 스트리밍 메시지나 원본 적재는 Avro가 일반적인 선택입니다.

파티셔닝과 버케팅의 차이는 무엇인가요

파티셔닝은 디렉터리를 나눕니다. 조회 조건에 파티션 컬럼이 있으면 디렉터리째로 건너뜁니다(partition pruning). 카디널리티가 높으면 디렉터리가 폭발합니다.

버케팅은 해시로 고정 개수의 파일에 나눕니다. 같은 키가 같은 버킷에 모이므로 조인 시 셔플을 줄일 수 있습니다(같은 버킷 수·같은 키로 버케팅된 테이블끼리). 카디널리티가 높은 컬럼(user_id 등)에 적합합니다.

요즘도 Hadoop을 쓰나요

HDFS + MapReduce 조합은 많이 줄었습니다. 저장은 오브젝트 스토리지(S3, GCS)로, 연산은 Spark/Flink로, 자원 관리는 Kubernetes로 옮겨가는 흐름입니다.

다만 개념은 그대로 유효합니다. 블록·스플릿·파티션, 셔플, 데이터 지역성, small files, 컬럼너 포맷은 지금 쓰는 도구들의 바탕에 그대로 남아 있습니다. 면접에서 Hadoop을 묻는 이유도 대개 이 개념 이해를 확인하려는 것입니다.