1.
Apache Hive는 Hadoop 기반의 데이터 웨어하우스 시스템으로, HDFS, S3 등에 저장된 대량의 데이터 대상으로 SQL을 사용할 수 있도록 도와줌 Hive 는 데이터를 따로 저장하는 storage 가 아님, 다른 저장소(HDFS, S3) 에 있는 데이터 기반의 작업을 실행하는 것임 (근데 그 작업이 쿼리를 실행하는 작업) 쿼리를 실행 할 때는 다음과 같은 요소들을 사용 - Hive Query Engine 에서 HiveQL로 작성된 쿼리를 실행 계획으로 변환하고 실행 - Execution Engine Hive 에서 쿼리를 실제 실행 (MapReduce, Tez, Spark 등의 엔진 사용) Hive 가 HDFS 내의 데이터를 읽으려면 HDFS 내의 데이터가 규칙적인 path(by partitioning) 및 파일 포맷(Orc, Parquet, Text 등)을 갖고 있어야 함 HDFS 의 데이터에 대한 메타 정보(데이터베이스, 테이블, 컬럼, 파티션, 파일 포맷, 데이터 위치 등)는 Hive Metastore 에 구조화된 형태로 저장됨 테이블 정의와 파티션 정보도 메타스토어에 저장됨. 테이블이 HDFS 내의 어느 디렉토리에 저장되어 있는지, 각 파티션이 어떤 경로에 위치하는지 등의 정보가 메타스토어에 기록됨 create external table 을 사용하여 테이블을 만들고 location 을 설정했다면, 사용자가 hive 를 통하지 않고 직접 HDFS 에 데이터를 넣었어도 Hive 에서 해당 location 에 접근해서 (create external table 실행할 때 미리 생성해둔 ) metadata를 기반으로 데이터를 읽을 수 있음(schema-on-read) 다시 말해, 테이블이 Hive Metastore에 존재하면, 해당 테이블의 메타데이터를 통해 HDFS에서 실제 데이터를 찾을 수 있기 때문에 사용자가 직접 데이터를 HDFS 에 저장했더라도 쿼리가 가능함 Hive 에서 처리하는 "데이터베이스", "테이블" 이라는 개념은, HDFS 데이터를 구분하고 관리하기 위한 논리적인 개념임 (실제 HDFS 에 "데이터베이스", "테이블"이 있는 것이 아님) 실제 HDFS 의 directory 가 Hive 에서 바라볼 때 "데이터베이스"가 됨 그리고 데이터베이스 dir 아래 위치한 dir 혹은 파일이 "테이블"이 됨 Hive는 배치 처리 시스템이기 때문에, 실시간 데이터 분석에는 부적합함. Presto 같은 실시간 쿼리 엔진 사용하면 됨 그리고 Hive는 기본적으로 Append-only 모델이기 때문에, 데이터를 삭제하거나 업데이트하는 것이 어려움. ACID Transactions(Hive 3.0 이상) 또는 Hudi, Iceberg 같은 테이블 포맷 사용하여 해결 |
하이브에서 작성된 쿼리는 일련의 job(MR, spark, etc)으로 변환되어 실행됨 하이브는 HDFS 에 저장된 데이터에 스키마를 입히는 방식으로 데이터를 테이블로 구조화 (읽기 스키마) 테이블 스키마, 파티션 같은 메타데이터를 메타스토어라 불리는 DB(MySQL, derby 등) 에 저장 메타스토어가 로컬 머신에 있으면, 한번에 한명의 유저만 사용 가능(derby DB를 사용하지 말아야 하는 이유) 실제 운영 환경에선 공유 원격 메타스토어를 사용 Hive 는 HADOOP_HOME 환경변수가 설정되어 있다면 그 정보를 이용하여 HDFS 접근 및 사용 가능함 hive 가 hdfs-site.xml 까지 도달 가능한 classpath 를 알고 있다면 hdfs-site.xml 에서 Name Node 주소와 포트 등의 정보를 토대로 HDFS 접속 정보를 얻음 이렇게 획득한 HDFS 접속 정보를 기반으로, Hadoop HDFS 클라이언트 라이브러리(Hadoop의 Java API)를 사용하여 HDFS에 직접 접근함 HIVE_HOME/conf/hive-env.sh 에 HADOOP_HOME 을 추가하여, hive 가 hadoop 정보를 얻을 수 있도록 함 |
'hive' 명령어를 사용하면, 사용자 머신에 메타스토어 데이터베이스를 만듦 hive 명령어 실행한 위치에 metastore_db 라는 디렉터리 만들어 그 안에 필요한 파일 저장 local 데이터를 읽고 local 에 저장할 수 있음 저장시 데이터를 변경하지 않고 그대로 저장 local 에 저장할 때 하이브가 저장하는 경로는 웨어하우스 디렉터리(기본값 /user/hive/warehouse) 하이브는 특정 테이블 질의할 때 모든 파일을 다 읽음 그래서 효율적인 쿼리를 위해 버켓팅, 파티셔닝이 필요함 |
하이브 속성 설정 우선순위 1. hive> 에 넣는 SET 명령어 2. 명령어에 넣는 -hiveconf 옵션 3. *-site.xml 4. *-default.xml |
Hive 쿼리 실행 엔진은 MR, Tez, Spark 를 지원 개발자가 Hive 에 실행한 '쿼리'는 각 '실행 엔진' 에 맞는 형태로 변경된 후 실행 엔진이 실질적으로 작업을 수행함 - 개발자가 작성한 HiveQL 쿼리 파싱 및 분석 - 분석한 내용을 토대로 논리적인 실행 계획 생성 - Hive의 최적화 엔진을 통해 규칙 기반 및 비용 기반 최적화를 거침 (조인 순서 변경, 조건 푸시다운, 파티션 필터링 등) - 최적화된 논리적 실행 계획은 최종적으로 선택된 실행 엔진 (MapReduce, Tez, Spark 등)이 이해하고 실행할 수 있는 물리적인 실행 계획으로 변환. 예를 들어 MR 의 경우, ResourceManager에 Job 제출하고, NodeManager에서 Map 및 Reduce 태스크를 실행. 여러 단계의 Map 및 Reduce 작업으로 구성된 Job으로 변환된 후, MR 작업 실행 Spark의 경우, Master 노드에게 애플리케이션을 제출하고, Worker 노드에서 RDD 연산 분산 방식으로 수행. RDD (Resilient Distributed Dataset) 연산 그래프(DAG)로 변환 후, 다양한 트랜스포메이션과 액션을 통해 작업 실행 |
hive-site.xml 에 아래와 같이 실행 엔진을 변경할 수 있음 - <property> <name>hive.execution.engine</name> <value>tez</value> </property> 혹은 아래와 같은 set 명령어로 설정 가능 - SET hive.execution.engine=spark; |
SparkSQL 이 존재함에도 불구하고 Hive 를 사용하는 이유 - 이미 시스템에서 Hive 를 사용하고 있기 때문에 - Hive metastore 를 범용적으로 사용하기 위해 Hive 가 관리하는 metastore 에는 테이블 스키마, 파티션 정보, 데이터 위치 등의 메타데이터가 포함되어있는데 이 정보를 (SparkSQL 포함하여) Hadoop Ecosystem 들이 필요로 하여 Hive metastore 를 (메타 데이터를 공유하면서) 사용함 |
2.
하이브 서비스 - cli : hive 명령어를 통해 실행. terminal 에서 곧바로 hiveQL을 사용할 수 있음 HDFS 및 metastore 에 직접 접근함. 단일 사용자만 사용 가능. 접근 권한 확인 하지 않아서 되도록 hiveserver2 사용 - hiveserver2 : hiveserver2 명령어를 통해 실행 다른 언어로 개발된 클라이언트와 연동 가능하도록 하이브 쓰리프트 서비스 실행 hiveserver2 로 thrift RPC 서비스가 실행되고, 이를 통해 다른 언어로 개발된 다른 프로그램에서 thrift, JDBC, ODBC 연결자로 하이브에 연결 가능(기본 포트 10000번) 즉, 다른 프로그램 이를테면 Tabealu 가 (client로서) hiveserver2 를 이용하여 hive 를 사용할 수 있음 (hiveserver2 는 마치 문지기, API 같은 느낌) hiveserver2 를 이용하면, 여러 클라이언트가 동시에 Hive에 접속하여 쿼리를 실행할 수 있음 다른 프로그램에서 접근하기 위해 hiveserver2 는 항시 데몬으로 동작중이어야 함. 접근 권한 확인 등을 hiveserver2 에서 진행 - beeline : beeline 명령어를 통해 실행 JDBC 로 hiveserver2 프로세스에 접근하는 명령행 인터페이스 즉, beeline 이 client 로서 hiveserver2 를 통해 hive 에 접근함. 그리고 사용자 행동(쿼리를 날리는 등)을 하겠지. - hwi : 하이브 웹 인터페이스 - 메타스토어 : Hive 테이블의 스키마, 위치, 파티션 정보 등의 메타데이터를 중앙 집중식으로 관리하는 서비스 기본적으로 메타스토어는 하이브 서비스와 동일한 프로세스에서 실행됨 메타스토어는 (HiveQL 과 상관없는) 독립적인 프로세스에서 실행됨 Hive CLI, HiveServer2, SparkSQL 등 다양한 Hive 관련 컴포넌트들이 Metastore에 접근하여 메타데이터를 공유하고 이용함 SPOF 이므로, HA 가 필수임. |
3.
메타스토어는 하이브 메타데이터를 저장하는 핵심 저장소 메타스토어는 서비스와 데이터 보관 저장소(DB)로 나뉨 - 메타스토어 서비스 (API) : Hive 클라이언트 (CLI, HiveServer2, SparkSQL 등)가 메타데이터에 접근할 수 있도록 인터페이스를 제공하는 서비스. 클라이언트는 직접 메타스토어 데이터베이스에 연결하는 대신 메타스토어 서비스를 통해 필요한 메타데이터를 요청하고 응답받음. Thrift 프로토콜을 사용하여 client 가 메타스토어서비스로 접근할 수 있는 API 제공함 - 메타스토어 저장소 (DB) : Hive 테이블의 스키마 (컬럼 이름, 데이터 타입 등), 데이터 위치 (HDFS 경로), 파티션 정보, 속성 등 실질적인 메타데이터를 저장하는 영구적인 저장소 < 내장 메타스토어 (embedded metastore) > - 메타스토어 서비스 : 하이브 서비스(beeline, hiveserver2 등)가 실행하는 동일한 JVM 내에서 실행됨 - 메타스토어 저장소(DB) : 하이브 서비스(beeline, hiveserver2 등)가 실행하는 동일한 JVM 내에서 실행됨 local 에 데이터 저장하는 derby 데이터베이스가 사용됨 Hive CLI, HiveServer2를 실행하는 JVM 프로세스가 시작될 때 Derby도 함께 시작되고, 이 프로세스가 종료될 때 Derby 데이터베이스도 함께 종료됨 (생애주기를 함께 함) 만약 Hive 서비스를 운영하는 서버가 예기치 않게 다운되거나 재시작되는 경우, 메모리 상의 변경 사항이 디스크에 완전히 기록되지 않았을 가능성이 있으며, 이는 데이터 손실로 이어질 수 있음. (다 저장 못 했는데 서버가 다운되면, 저장 진행중이던 데이터가 날아갈 수 있다는 말임) derby 는 한 번에 db파일 하나에만 접근 가능해서 하나의 하이브 세션만 사용 가능 (다른 세션에서 beeline 이 hive 접근시 오류 발생...) (다른 사용자 등에 의해) 두 번째 세션 사용 불가 따라서 다중 세션(다중 사용자) 지원 불가 < 로컬 메타스토어 (Local Metastore) > - 메타스토어 서비스 : 하이브 서비스(beeline, hiveserver2 등)가 실행하는 동일한 머신에서 실행됨 - 메타스토어 저장소(DB) : 별도의 머신에서 별도의 프로세스로 실행되는 데이터베이스. mysql, postgresql etc 다중 세션(다중 사용자) 지원 가능 mysql, postgresql 등을 원격 데이터베이스로 사용 hive-site.xml 파일에서 데이터베이스 연결 정보(JDBC URL, 드라이버 클래스, 사용자 이름, 비밀번호 등)를 설정해야 접근 가능함 < 원격 메타스토어 (Remote Metastore) > - 메타스토어 서비스 : 하나 이상의 메타스토어 서비스가, 하이브 서비스와는 별도의 독립적인 JVM 프로세스로 실행되는 서버에서 운영됨 - 메타스토어 저장소(DB) : 별도의 머신에서 별도의 프로세스로 실행되는 데이터베이스. mysql, postgresql etc hive 클라이언트(cli, hiveserver2, spark 등)와 메타스토어 서버는 thrift 프로토콜을 사용하여 통신함 hive-site.xml 파일에서 원격 메타스토어 서버의 URI(hive.metastore.uris)를 설정해야 접근 가능함 여러 대의 메타스토어 서버를 구성할 수 있기 때문에, 로드밸런싱이나 고가용성, 확장성 등 확보 가능! 데이터베이스 서버를 완전히 방화벽 뒤에 숨기고, Hive 클라이언트는 메타스토어 서버를 통해서만 메타데이터(DB)에 접근하므로 보안이 강화됨. 클라이언트는 데이터베이스 자격 증명을 가질 필요가 없음. DB 서버가 3대 클러스터로 구성되어있고, metastore server 가 한 대 있다고 하자. DB 서버는 metastore server 만 접근 가능하도록 설정되어 있어서 다른 client 의 접근이 차단됨 metastore server 로 접근은 오로지 hive clients 만 가능하도록 설정해둠 이런 식으로 hive client 가 직접 DB 에 접근하는 것을 방지하고, 메타스토어 서버라는 중개자(API)를 통해 접근하도록 하여 보안 강화! |
4.
rdb 와 hive 차이 - rdb 는 쓰기 스키마, hive 는 읽기 스키마 쓰기 스키마는 index 를 지원해서 쿼리가 빠르지만, 읽기 스키마는 디스크 직렬화가 필요없어서 데이터 write 가 매우 빠름 - rdb 의 트랜잭션, 색인 기능은 hive 에서 일부 지원 hive 는 기본적으로 데이터 update 를 못 함 트랜잭션(update)이 활성화된 hive 는 update 가 가능하지만, 실제 테이블 내 데이터가 업데이트를 하는 건 아니고 update 내역을 별도의 작은 델타 파일로 저장함 - hive 의 insert into : 하이브 테이블, 파티셔닝 된 테이블 내에 데이터를 추가하며 insert 함 insert overwrite : 하이브 테이블, 파티셔닝 된 테이블 내의 데이터를 모두 지우고 insert 함 - 데이터를 읽을 때 SHARED_READ lock 을 얻는데, 해당 lock 이 존재하면 다른 사용자가 읽기 가능, update 불가능 - 데이터를 update 할 때 EXCLUSIVE lock 을 얻는데, 해당 lock 이 존재하면 다른 사용자가 읽기/update 가 불가능 hive 가 지원하는 색인 - 콤팩트 색인 : HDFS 블록 넘버로 색인 - 비트맵 색인 : 특정 값이 출현하는 행을 효율적으로 저장하기 위해 압축된 비트셋으로 색인 색인을 위한 데이터는 별도의 테이블에 저장됨 |
6.
하이브 테이블의 데이터 저장소는 local disk, s3, HDFS 등 다양하게 사용 가능 관리 테이블 : 하이브가 데이터를 직접 관리 직접 관리한다고 해도, 데이터는 여전히 HDFS 등 외부 저장소에 있음 직접 관리한다는 의미는, 테이블이 삭제되었을 때 데이터가 실제로 삭제된다는 의미임 load 쿼리 사용시, 해당 데이터가 웨어하우스 디렉터리(local, HDFS 등)으로 이동 drop table 쿼리 사용시, 해당 데이터와 메타데이터가 실제로 삭제 외부 테이블 : 하이브가 데이터를 직접 관리하지 않음 drop 쿼리 사용시, 메타데이터만 삭제되고 데이터는 삭제되지 않음 |
< 파티션 > 데이터를 각 dir 에 나눠 저장. PARTITIONED BY year=2024/month=01/ 같은 구조로 HDFS에 저장됨. < 버킷 > 지정한 컬럼값을 해쉬 처리 한 후, 버킷수로 나눈 나머지만큼 파일로 나눠 저장. dir 가 아닌 파일에 저장. CLUSTERED BY 버킷을 사용하는 이유 - 매우 효율적인 쿼리가 가능 테이블에 대한 추가 구조를 부여하게 되고, 쿼리 수행 시 이 추가 구조 사용 가능 - 효율적인 샘플링에 유리 - 버켓팅한 테이블은 조인시에 SMB(sort merge bucket) 조인으로 처리하여 속도 향상 |
row format : 행 구분자 설정, 특정 행의 필드가 저장된 방식 설정 - 지정가능한 구분자 FIELDS TERMINATED BY '\t' -- 칼럼을 구분하는 기준 COLLECTION ITEMS TERMINATED BY ',' -- 리스트를 구분하는 기준 MAP KEYS TERMINATED BY '=' -- 맵데이터의 키와 밸류를 구분하는 기준 LINES TERMINATED BY '\n' -- 로(row)를 구분하는 기준 ESCAPED BY '\\' -- 값을 입력하지 않음 NULL DEFINED AS 'null' -- null 값을 표현(0.13 버전에서 추가) - 특정 행의 필드 저장 방식 : 데이터 저장시 SerDe 를 통해 직렬화하여 저장하고 읽을 때 역직렬화하여 읽나 봄 기본서데, 정규식(RegExSerDe), JSON(JsonSerDe), CSV(OpenCSVSerde)가 존재함 "나는 이 테이블에 데이터를 저장할 때 지정된 SERDE를 사용하여 데이터를 직렬화하고, 이 테이블에서 데이터를 읽을 때도 동일한 SERDE를 사용하여 데이터를 역직렬화하겠다!" 라는 의미임 stored as : 데이터를 저장하는 파일 포맷 지정 저장 포맷은 TEXTFILE, SEQUENCEFILE, ORC, PARQUET 등이 존재 바이너리인 sequence, orc, parquet 등은 행의 형식이 바이너리 포맷에 따라 결정되므로 row format 지정 불필요 참고 https://wikidocs.net/23469 |
hive 는 읽기 스키마를 사용하기 때문에 테이블의 이름 변경, 테이블의 정의 변경, 새로운 컬럼 추가 등이 자유로움 |
셔플 조인은 가장 느린 조인
맵(Map) 단계에서 각 테이블을 읽고, 조인 컬럼을 키로 설정하여 셔플
리듀서로 데이터가 이동되고 리듀서에서 테이블을 조인
버켓팅 되어있으면 Bucket Map Join 이 빨라짐.
join 의 기준이 되는 key 들이 모두 버케팅 되어있는 상황에서 Join 을 진행하면,
작은 테이블의 버킷들(Table a, Table c)이 큰 테이블의 버킷(Table b)의 메모리에 모두 복사됨
이렇게되면 join 에 필요한 모든 key 가 하나의 Mapper 에서 접근 가능하기 때문에 join 속도 향상
작은 테이블 크기가 메모리에 올라갈 정도로 작아야 함
브로드캐스트 조인임.
Sort Merge Join 은 조인 테이블이 버켓팅 되어 있을 때 사용 가능
버켓팅된 키의 정보를 이용하여 빠르게 조인
다음 절차로 join 이 진행됨
- Table a 와 Table b 에서 join 에 필요한 데이터를 읽음
- 별도의 공간에서 읽은 데이터를 정렬sort 함
- 정렬된 데이터를 기준으로 join 함
참고 : https://coding-factory.tistory.com/757
hive 명령어와 beeline 명령어 차이?
- hive 명령어는 하이브 옵션 설정, 쿼리 실행 등이 가능
- beeline 은 단지 hive 에 thrift 로 접근하는 인터페이스
< thrift >
다양한 언어로 개발된 소프트웨어들을 쉽게 결합(통신)하는 프레임워크. 내부에서 RPC 사용
서로 다른 프로그래밍 언어로 작성된 서비스들이 효율적으로 통신할 수 있도록 도와줌
(클라이언트와 서버가 서로 다른 언어로 구현될 수 있음)
언어 간 상호 운용성(Cross-language interoperability)과 고성능 서비스 호출에 중점
데이터베이스 연결보다는 서비스 간의 통신에 더 적합함
HiveServer2 가 클라이언트와의 통신을 위해 Thrift API 를 사용함
< JDBC >
- Java Database Connectivity
- 오직 자바(Java) 언어를 위한 표준 데이터베이스 연결 API
- JAVA 언어로 DB 에 접근해 DML 쿼리 하기 위한 인터페이스(API)
- Java와 연동되는 DBMS에 따라 그에 맞는 JDBC를 설치할 필요가 있음
각 데이터베이스 벤더(Oracle, MySQL, PostgreSQL, SQL Server 등)는 자신들의 데이터베이스에 특화된 JDBC 드라이버를 제공하며, 이 드라이버는 JDBC 인터페이스를 구현한 것임
즉, 각 DB 제품들마다 JDBC 를 지원하는 자신만의 드라이버를 구축해두었음(이 드라이버는 관리자가 받아서 설치해야 함)
하지만 각 DB 에 연결하기 위해 각 DB 가 구축해둔 드라이버에 따라 접근 방법을 바꿀 필요는 없음
클라이언트(자바 애플리케이션)는 그냥 표준 JDBC 인터페이스를 사용하여 DB 연결 코드를 작성하면 됨
실제 DB 에 연결되는 과정에서, 각 DB 가 구축한 JDBC 드라이버가 담당하여 자신의 고유한 네트워크 포로토콜로 변환한다고 함
< ODBC >
- Open Database Connectivity
- 응용프로그램에서 다양한 DB 에 접근해 DML 쿼리하기 위한 인터페이스
- 접속처의 데이터베이스가 어떠한 DBMS에 의해 관리되고 있는지 의식할 필요가 없음
애플리케이션이 어떤 프로그래밍 언어로 작성되었든 (C 언어 바인딩이 가능한 언어라면)
다양한 데이터베이스 관리 시스템(DBMS. MySQL, PostgreSQL... 등등)에 접근할 수 있는 공통적인 방법 제공
(JDBC보다 더 넓은 언어 범위를 커버)
(JDBC 와 마찬가지로) 각 데이터베이스 벤더는 자신들의 데이터베이스에 특화된 ODBC 드라이버를 제공
(관리자는, 사용하려는 데이터베이스(MySQL, PostgreSQL, Hive)에 맞는 ODBC 드라이버를 운영체제에 미리 설치해야 함)
(JDBC 와 마찬가지로) 클라이언트(애플리케이션)는 표준 ODBC API 함수(인터페이스)를 사용하여 DB 연결 코드를 작성
실제 DB 에 연결되는 과정에서, 애플리케이션의 연결 호출은 먼저 ODBC 드라이버 관리자에게 전달됨
드라이버 관리자는 애플리케이션의 요청을 파싱하여, 어떤 특정 ODBC 드라이버가 필요한지 식별
그리고 해당 드라이버를 로드하고, 애플리케이션의 요청을 로드된 드라이버에게 중계(forward)함
드라이버 관리자로부터 연결 요청을 받은 해당 데이터베이스의 ODBC 드라이버는 이 요청을 받아서,
자신에게 맞는 데이터베이스의 고유한 네트워크 프로토콜로 변환하여 실제 데이터베이스와 통신함
개발자는 그냥 표준 ODBC API 를 사용하면 됨.
hive 에서 orc 를 사용하는 이유
- 높은 압축률
- 컬럼 기반 포맷이라 처리 속도가 빠름
- 스키마를 가지고 있음
- orc 는 hive 에 최적화되어있고, parquet 은 spark 에 최적화 되어있음
ORDER BY vs DISTRIBUTE BY vs SORT BY vs CLUSTER BY
ORDER BY
- 매퍼에서 나오는 모든 데이터를 하나의 리듀서로 몰아서 정렬 수행
- 리듀서가 하나 뿐이라, 저장되는 파일도 하나
- limit 을 추가하여 리듀서에 부하를 줄이는 게 좋음
- order by COLUMN
SORT BY
- ORDER BY 와 다르게, 리듀서가 하나 이상, 각 리듀서에서 정렬 수행
- 각 리듀서별로 정렬하기 때문에, 모든 리듀서 결과는 전체 정렬 되어있지 않음
- 리듀서 개수를 1로 설정하면 ORDER BY 와 같은 결과
- sort by COLUMN
DISTRIBUTE BY
- distributed by 의 대상이 되는 컬럼의 값 기준으로 group 지어 하나의 리듀서에 들어감
- 정렬 수행하지 않음
- 예)
정렬 대상 : a a b c c c d
리듀서 1) a d a
리듀서 2) c b c c
(리듀서 개수와 상관 없이) 같은 값은 모두 하나의 리듀서에 몰려 있음.
CLUSTER BY :
- distributed by 와 sort by 를 같이 사용
- 즉, distributed by 실행하며 정렬까지 진행
- 예)
정렬 대상 : a a b c c c d
리듀서 1) a a d
리듀서 2) b c c c
참고) https://saurzcode.in/2015/01/hive-sort-order-distribute-cluster/
Hive 정적 파티션 vs 동적 파티션
정적 파티션
- 데이터의 테이블에 파티션 값을 직접 입력
예)
INSERT INTO TABLE tbl(yymmdd='20220625')
SELECT name FROM temp;
> hdfs://hive/tables/yymmdd=20220625/
동적 파티션
- 데이터의 컬럼값을 기준으로 파티션이 생성됨
- 쿼리 시점에 어떤 데이터가 어떤 파티션에 가는지 모름
- 동적 파티션은 느림
예)
INSERT INTO TABLE tbl(yymmdd)
SELECT name, yymmdd FROM temp;
> hdfs://hive/tables/yymmdd=20220625/
> hdfs://hive/tables/yymmdd=20220626/
> hdfs://hive/tables/yymmdd=__HIVE_DEFAULT_PARTITION__/
HDFS 에서 작은 파일들 합치기
https://gyuhoonk.github.io/hive-merge-query
결론
작은 파티션들이 많으면, HDFS IO 도 많아지고 NN memory 에 부담도 커짐
Hive
- insert into 등의 쿼리는 매퍼만 동작하는데,
매퍼에서 읽은 데이터를 그대로 HDFS 블럭으로 저장하기 때문에 블럭 개수가 늘어남
이를 합쳐주기 위해 (sort by 등을 추가하여) 리듀서를 추가
Spark
- 셔플 파티션은 기본값이 200 이라서, 셔플 후에는 200개의 작은 파티션들이 생성되어 HDFS 에 저장됨
이를 합쳐주기 위해 셔플 파티션 값을 조정하거나, repartition 혹은 coalesce 를 사용하여 파티션 개수 줄임
< Presto >
Apache Presto 는 Hive 와 마찬가지로, 대규모 데이터에 대한 SQL 기반 쿼리 처리 시스템 Hive 처럼 외부 스토리지(HDFS, S3)에 저장된 데이터 대상으로 쿼리를 사용할 수 있도록 도와줌 하지만 Hive와 다른 목적과 작동 방식을 갖음 - 목적 - Hive : batch 쿼리 처리 - Presto : realtime 분석 쿼리 처리 - 실행 엔진 - Hive : MR, Tez, Spark - Presto : 자체 엔진(MPP:massively parallel processing) - 처리 방식 - Hive : 디스크 기반 - Presto : in-memory 기반 - 속도 - Hive : 대용량 데이터 처리하므로 느림 - Presto : 빠름 (...) - 데이터 소스 - Hive : HDFS, ORC, Parquet - Presto : HDFS, ORC, Parquet, MySQL, Kafka, Cassandra 등 다양하게 지원 - 사용 사례 - Hive : 대량 데이터 ETL, 데이터 웨어하우스에서 OLAP 에 사용 - Presto : BI, 실시간 대시보드, 쿼리 성능이 중요한 환경, 대화형 분석 환경 제공 Presto 로 대용량 데이터 ETL 혹은 배치 처리하기는 부적합함. 이런 경우는 Hive 를 사용하고, 실시간 분석 처리할 때 Presto 사용 Hive 와 Presto 를 혼합하여 사용하기도 함 이를테면, 대량의 데이터를 HDFS 에 적재할 때는 Hive 를 사용하고, 데이터를 조회할 때는 Presto 를 사용하는 식. |
< Iceberg >
Apache Iceberg 는 대규모 데이터 레이크에서 테이블을 효율적으로 관리하기 위해 설계된 테이블 포맷임 (데이터 포맷 아님) Iceberg는 데이터 레이크를 데이터웨어하우스처럼 활용할 수 있게 해줌 HDFS, S3 등 다양한 스토리지에서 대량의 데이터를 안정적으로 관리하고 빠르게 쿼리할 수 있도록 최적화 됨 Iceberg 의 장점은 다음과 같음 - 대용량 데이터(수십~수백 페타바이트) 처리 최적화 - ACID 트랜잭션 지원 (데이터 일관성 보장) (ACID : 원자성(Atomicity), 일관성(Consistency), 격리성(Isolation), 지속성(Durability) ) - Schema Evolution 지원 (스키마 변경 가능) - Partition Evolution 지원 (파티셔닝 변경 가능) - Time Travel 지원 (과거 데이터 조회 가능) - 다양한 엔진(Hive, Spark, Trino, Flink, Presto)과 호환 Iceberg 테이블에 저장되는 데이터는 Parquet, ORC 같은 포맷을 갖음 이 데이터 파일들은 한 번 생성되면 절대 변경되지 않음 (심지어 실제 데이터 삭제도 안 됨) 업데이트, 삭제 등은 새로운 파일을 생성하는 것으로 (논리적으로) 처리됨 그리고 테이블에 추가된 데이터들 대상으로 메타데이터(데이터 파일의 경로, 파티션 정보, 컬럼별 통계(최소/최대 값, Null 개수 등), 삭제 정보 등)를 미리 갖추고 있음 예를 들어보자 내가 Iceberg 테이블을 처음 생성했다고 하자 이 Iceberg 테이블 내 아직 데이터 파일은 없음 /user/hive/warehouse/my_sales/metadata/ 경로에 초기 테이블 메타데이터 파일(예: v1.metadata.json)이 생성 이 파일은 비어있는 초기 스냅샷을 가리킴 /user/hive/warehouse/my_sales/ └── metadata/ └── v1.metadata.json <- '아무 데이터도 없이 빈 현재 테이블' 상태을 나타내는 스냅샷 .current 포인터가 v1.metadata.json을 가리키게 됨 내가 select 쿼리를 실행해도 (v1 스냅샷을 기준으로) 데이터가 없기 때문에 아무것도 출력되지 않음 내가 어떤 데이터를 (Parquet 포맷으로) 삽입함 (insert into) part-00000-abc.parquet 이라는 이름으로 저장됨 /user/hive/warehouse/my_sales/
├── data/ │ └── year=2023/month=01/day=01/ <- 파티션은 (내가 미리 설정한 것 기반으로) 자동 생성됨 │ └── part-00000-abc.parquet <- 내가 저장한 데이터 └── metadata/ ├── v1.metadata.json ├── snap-1-m0.avro <- '내가 저장한 데이터(part-00000-abc.parquet)' 의 메타데이터(경로, 통계 등)를 갖는 menifest 가 생김 ├── snap-1-ml.avro <- 매니페스트 파일(snap-1-m0.avro) 정보가 담긴 menifest 가 생김 └── v2.metadata.json <- '내가 저장한 데이터 하나가 존재하는 테이블' 상태를 나타내는 스냅샷이 새로 생김 .current 포인터가 v2.metadata.json을 가리키게 됨 내가 select 쿼리를 실행하면 (v2 스냅샷을 기준으로) 데이터(part-00000-abc.parquet) 가 출력됨 내가 아까 넣은 데이터를 지우는 쿼리를 실행함 (delete from MYTABLE where id = 1;) /user/hive/warehouse/my_sales/
├── data/ │ └── year=2023/month=01/day=01/ │ ├── part-00000-abc.parquet <- 실제 데이터는 삭제되지 않음 │ └── deleted-rows-xyz.avro <- 논리적으로 삭제되었다는 마크가 추가됨. (records id=1 was deleted 같은 내용이 있음) └── metadata/ ├── v1.metadata.json ├── snap-1-m0.avro ├── snap-1-ml.avro ├── v2.metadata.json ├── snap-2-m0.avro (Manifest File: lists part-00000-abc.parquet AND deleted-rows-xyz.avro) ├── snap-2-ml.avro (Manifest List: lists snap-2-m0.avro) └── v3.metadata.json <- '삭제가 진행된 테이블' 상태를 나타내는 스냅샷이 새로 생김 Iceberg는 최신 스냅샷(v3)을 참조하여 part-00000-abc.parquet를 읽긴 하지만... deleted-rows-xyz.avro를 참조하여 id=1인 레코드를 최종 결과에서 제외 사용자 입장에서는 '쿼리 결과를 보니 데이터가 삭제되었네?' 처럼 보임 업데이트 하는 상황을 보자. UPDATE my_sales SET amount = 120 WHERE id = 1; 같은 쿼리를 실행하면 Iceberg 는 update 를 '기존 데이터 삭제' + '새 데이터 추가' 로 해석하고 처리함 즉, (delete from 처럼) id=1 인 데이터 삭제하고, id=1 amount=120 인 새로운 데이터를 추가함 /user/hive/warehouse/my_sales/ ├── data/ │ └── year=2023/month=01/day=01/ │ ├── part-00000-abc.parquet <- 아직도 연명중 │ ├── deleted-rows-xyz.avro <- 지웠던 흔적도 고스란히 남아있음 │ └── part-00001-def.parquet <- 업데이트하면서 새로 추가된 새로운 데이터 └── metadata/ ├── ... (previous metadata files) ├── snap-3-m0.avro (Manifest File: lists old valid, new delete, new insert files) ├── snap-3-ml.avro └── v4.metadata.json <- '업데이트 한 데이터가 포함된 테이블' 상태를 나타내는 스냅샷이 새로 생김 .current 포인터가 v4 스냅샷을 바라보게 됨 사용자는 이 스냅샷 상태의 테이블을 기준으로 쿼리하게 되므로, 업데이트하여 새로 추가된 데이터를 select 할 수 있음 기존 데이터 파일을 변경하지 않고(불변) 메타데이터만 업데이트하여 컬럼 추가/삭제/이름 변경 등을 안전하게 수행 기존 데이터 파일이 남아있으니, 과거 스냅샷을 참조하여 과거 특정 시점의 데이터 상태를 쿼리 가능! 문제가 발생했을 때도 과거 스냅샷 참고하여 테이블을 이전으로 쉽게 되돌릴 수 있음(롤백 가능) Iceberg 테이블에 데이터를 쓰는 시스템, Spark, Hive 등이 주체가 되어 iceberg 스냅샷을 추가하고, 매니페스트를 추가함. 예를 들어 Spark 에서 iceberg 테이블에 데이터를 쓴다고 가정해보자 Executor 내 모든 Task가 데이터 파일/삭제 파일 작업을 완료하면, Spark Driver는 새로 생성된 이 파일들에 대한 메타데이터(경로, 통계, 파티션 정보 등)를 수집함 이렇게 수집한 정보를 바탕으로 새로운 매니페스트 파일과 스냅샷을 생성하고 /metadata/ 에 저장함 Spark Driver 가 어떻게 Iceberg 매니페스트/스냅샷 생성하는 방법을 알고 있을까? 바로 Spark 가 Apache Iceberg 가 제공하는 핵심 라이브러리를 사용하기 때문. 이 라이브러리를 이용하여 매니페스트/스냅샷을 생성하는 방법을 알게 됨 |
'Hadoop' 카테고리의 다른 글
[Hadoop] YARN Resource Manager WebUI 설명 (1) | 2025.05.25 |
---|---|
HDFS path 에 사용하는 와일드 카드, Globbing (0) | 2023.09.13 |
[YARN] Fair Scheduler 설명 링크 (0) | 2022.05.30 |
[Hadoop] HDFS 디렉터리/파일들을 har 파일 하나로 archiving 하는 방법 (1) | 2022.04.01 |
[HDFS] 내가 맞닥뜨린 Permission denied 이슈 (2) | 2022.01.18 |