본문 바로가기
개발공부 개발새발/Hadoop

Hadoop ) Iceberg hive catalog

by 휴일이 2025. 6. 22.

RDB 와 Hadoop 의 차이

Rdb는 공유 스토리지를 사용하기 때문에 데이터 저장량이 늘어나고 공유스토리지 연산 컴퓨팅 리소스가 늘어나면 일정 수준 이상으로 성능을 올리면 i/o가 문제가 생기는데 하둡은 그렇지 않은 이유

공유 스토리지 : 서버가 데이터를 찾기 위해 디비 서버에 직접 접근하는 것 → 중앙 저장소, 모든 I/O 요청이 공유 스토리지로 집중되는 구조

  • 공유 스토리지는 데이터를 한 곳에 저장하니 트랜잭션 관리가 쉽다.
  • 하지만 요청이 한 서버로 몰리기 때문에 Disk I/O 가 병목될 수 있으며 고가용성을 위해 스토리지 레벨 또는 로그로 복제한다.

하둡은 분산 로컬 스토리지

하둡의 저장 구조는 HDFS (Hadoop Distributed File System)

 

구성 요소 설명
NameNode 메타데이터 관리 (파일 이름, 블록 위치 등)
DataNode 실제 데이터 저장 (각 노드의 로컬 디스크)
블록 분산 저장 하나의 파일을 여러 블록으로 나누고, 서로 다른 노드에 분산 저장
복제(replication) 기본적으로 각 블록은 3개 복제 (고가용성 보장)
  • 분산 저장 + 분산 연산
    • 저장, 계산 전부 각 노드의 로컬 디스크를 사용한다. → 중앙 스토리지 병목 없음
  • 데이터가 있는 노드에서 연산 실행
    • 연산이 거창한 게 아니라 그냥 데이터가 있는 노드에서 조회한다고 보면 된다. 다른 노드에서 가져와서 조회한다가 아닌 가지고있는 노드에서 직접 조회한다는 것임
  • 스케일 아웃이 매우 쉽다
    • 노드를 추가하면 저장량도 연산력도 비례적으로 증가

엥 그럼 RDB 는 어떻게 스케일 아웃함?

  1. 샤딩
    • 데이터를 물리적으로 다른 서버에 분산 저장
      • user_id % 3 == 0 → DB1
      • user_id % 3 == 1 → DB2
      • user_id % 3 == 2 → DB3
    • 운영 복잡도 매우 증가 ㄷㄷ → 실제로 잘 사용하나
  2. Read-Write 분리
    • 읽기는 slave 쓰기는 master
    • 로그 기반으로 복제되기도 함
    • 완전한 수평확장은 아님

그럼 하둡은???

처음부터 데이터를 분산 저장하도록 설계

  1. 데이터를 작은 블록(기본 128MB) 로 나눈다.
  2. 여러 노드에 분산해 저장한다.
  3. 복제까지 자동으로 관리한다. (기본 3개)
  4. 연산(조회)도 그 노드에서 바로 수행 → 데이터 이동 최소화
    • 연산은 Spark, MapReduce 같은 애들이 직접 데이터 있는 노드에서 수행

연산을 그 노드에서 수행한다는 게 뭔말임???

Spark 기준

  1. Spark Driver가 네임노드에서 파일 블록 위치(=DataNode)를 알아냄
  2. 각 Executor(Task)가 그 데이터가 위치한 노드에 자동 배치됨
  3. 그 Executor는 로컬 디스크에서 .parquet 파일을 직접 읽고, filter, map, groupby 같은 연산을 그 자리에서 수행함
  4. 필요한 결과만 최소로 네트워크로 전송

예시

val df = spark.read.parquet("hdfs:///warehouse/user_log/")
val filtered = df.filter($"user_id" === 12345)

이 코드를 Spark가 처리한다면

  • user_log 데이터는 worker-1, worker-2, worker-3에 각각 나뉘어 저장
  • Spark는 각 worker 노드에 Task를 분산함
  • 예를 들어 user_id=12345가 worker-2의 .parquet 에 있으면
    • 그 filter는 worker-2의 Executor가 직접 수행함 → data locality
    • 다른 노드로 데이터를 옮기지 않아도 됨
    • 그 필터링된 결과만 나중에 Spark Driver나 앱으로 전송됨
구분 설명
❌ “연산을 마스터 노드에서 수행한다” 데이터를 전부 가져와서 마스터에서 계산 → 비효율
✅ “연산을 데이터 노드에서 수행한다” 데이터를 보관 중인 노드에서 계산까지 수행 → 네트워크 부하 ↓
📌 핵심 필터링, 집계, 변환 등을 가진 곳에서 직접 하고, 최소한의 데이터만 전송함

→ 그냥 그 데이터 노드에서 직접 연산을 수행한다는 말이 맞쬬?

Hive metastore

RDBMS 테이블 형식으로 파일의 메타데이터를 저장하자! → 회사에선 Postgres 를 쓴다네

  • Hive가 사용하는 “카탈로그” 같은 역할
  • Spark, Trino 등도 이 Hive Metastore를 조회해서 “어떤 테이블이 있고”, “컬럼이 뭐고”, “어디 저장돼있고”, “무슨 포맷이야?” 를 알아냄

어떤 형식으로 저장되나염?

RDB 테이블 형식으로 다음과 가튼 메타데이터들 저장

 

테이블 이름 내용
DBS Hive 상의 Database들
TBLS 각 Database 안의 Table 목록
COLUMNS_V2 테이블/파티션의 컬럼 정보
SDS 테이블의 물리적 저장 포맷, 파일 경로
SKEWED_COL_NAMES, PARTITIONS 등 파티션 정보
SERDES, STORAGE_DESCRIPTIONS 입력/출력 포맷, 포맷 처리기
BUCKETING_COLS, SORT_COLS 버킷 컬럼, 정렬 등

실제 데이터를 저장하는 것은 아님

실제 데이터는 HDFS 등에 저장되는데, hive metastore 는 이 테이블이 “어느 위치”에 있고 “어떤 구성”을 하고 있는지만 알 수 있음.

  • 테이블 구조
  • 컬럼
  • 파티션
  • 저장 포맷
  • 파일 경로 등

그럼 누가 사용함?????

회사에서 쓰는거 기준으로 설명

  • Spark SQL
  • Trino
    • Trino에 쿼리했을 때 테이블 구조
  • Iceberg catalog ( Hive Catalog)
    • 아이스버그를 통해 하둡에 저장된 실제 데이터를 관리한다.

괜찮은 아키텍쳐

Iceberg hive catalog

  • 실제 데이터는 HDFS 에 저장되어 있고 아이스버그 테이블로 관리된다. 메타데이터는 하이브에 저장한다.
  • Spark , Trino 같은 시스템들이 Iceberg 테이블을 참고하여 데이터를 조회하는 등등

어떻게 구성 됨?

로그를 저장한다고 가정하자

  1. Iceberg 테이블 생성
-- Spark 또는 Trino에서 Iceberg 테이블 생성
CREATE TABLE db.user_log (
  user_id INT,
  log_time TIMESTAMP,
  dt STRING
)
PARTITIONED BY (dt)
STORED AS ICEBERG
LOCATION 'hdfs:///warehouse/user_log'

이 때

  • 테이블 구조 정보 → Hive metastore 저장 : 테이블명, 컬럼, 파티션 정보
  • Iceberg metadata files → HDFS : JSON 형식으로 Iceberg 전용
  • 실제 데이터 파일 → HDFS : Parquet 등으로 저장.
[1] Hive Metastore (외부 카탈로그)
   └── 테이블 이름, 위치, 스냅샷 참조 등

[2] Iceberg 메타데이터 파일
   └── manifest.json, snapshot.json 등 (버전 관리)

[3] 실제 데이터 파일
   └── Parquet, ORC 파일들 (HDFS, S3 등에 저장)

구조의 장점

장점 설명
💾 메타데이터 독립성 Iceberg는 자체적인 메타데이터 파일(manifest, snapshot)을 통해 성능 높임
🔁 스냅샷 관리 Iceberg는 Append-only 방식 + 스냅샷 기반 → Rollback, Time-travel 가능
🚀 쿼리 최적화 파일 단위로 filter-pushdown, schema evolution, hidden partitioning 가능
🌐 Hive Metastore 연동 기존 Hive 기반 플랫폼(Trino, Spark, Airflow 등)이 그대로 연동됨

만약 Spark 로 접근한다고 가정하면..

  1. spark 가 hive metastore 에서 테이블 위치를 알아냄.
  2. 위치에 있는 Iceberg metadata JSON 파일을 읽음.
  3. 어떤 시점의 snapshot 을 사용할 것인가 정하기. (어떤 시점의 데이터를 사용할 것인가?)
    • 아이스버그는 append only 로, 쓰기가 일어날 때마다 새로운 snapshot 생성 → 과거의 특정 snapshot 을 가져와 time travel 가능.
  4. 그 스냅샷에 연결된 manifest 파일을 열고 그 안에 있는 parquet 목록 파악
  5. 그 파일들을 spark 가 병렬로 읽는다.

Spark 는 어떻게 하이브 메타스토어에 접근이 가능할까? → HiveCatalog

spark.sql.catalog.my_catalog=org.apache.iceberg.spark.SparkCatalog
spark.sql.catalog.my_catalog.type=hive
spark.sql.catalog.my_catalog.uri=thrift://hive-metastore:9083

이렇게 설정할 경우, Spark 가 Iceberg 작업을 할 때

  • Iceberg API 로 메타데이터 쓰기
  • Hive metastore 에도 동시에 테이블 등록

HDFS 구조

/warehouse/user_log/
├── data/
│   ├── 00000-abc.parquet
│   └── 00001-def.parquet
├── metadata/
│   ├── v1.metadata.json
│   ├── v2.metadata.json
│   └── snapshots/
└── hive_metastore_entry (등록만 되어 있음, 실파일 없음)
  • hive_metastore_entry <<< 이건 실존하는 파일은 아님
    • Hive Metastore에 “이 테이블은 이 위치(hdfs:///warehouse/user_log/)에 있다”는 등록 정보만 있다 는 뜻
    • Hive Metastore는 실제 데이터를 저장하지 않고 → 테이블 이름 / 스키마 / 저장 위치 등의 메타 정보만 가지고 있음
    • Hive Metastore가 이 파일을 보고 아 여기에 파일이 있구나 표시하는 용도

요약

  • 스파크나 트리노에 쿼리로 데이터를 요청하면…
    • Spark/Trino에서 Iceberg 테이블에 쿼리 실행 시작
  • 일단 하이브와 통신하여 ‘데이터의 메타데이터를 저장 중인 아이스버그 테이블의 위치’를 알아내고
    • Hive Metastore에서 Iceberg 테이블의 ‘물리적 경로’를 얻어옴.
    • (예: hdfs:///warehouse/db/user_log/)
  • 테이블의 위치를 알아내면 아이스버그 테이블에 들어가 메타데이터를 확인하여 실제 데이터의 위치를 확인 후
    • Iceberg의 metadata/ 디렉터리에 있는 JSON 파일들 (snapshot, manifest)을 읽고 그 안에서 어떤 .parquet 파일이 존재하는지 확인함
  • 스파크가 실제 하둡 경로로 들어가 데이터를 읽어온다
    • 그 파일 목록을 가지고 Spark가 병렬로 HDFS에서 데이터를 읽어옴
    • Spark는 파일을 읽는 쪽도 분산돼 있고, Iceberg는 각 파티션/파일을 정교하게 추적하고 있어서 성능도 좋음
    • 트리노라면 트리노 worker 가 읽음.
728x90

'개발공부 개발새발 > Hadoop' 카테고리의 다른 글

Hadoop ) 로컬에 hadoop 3.2.2 설치하기  (3) 2025.06.25