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' 명령어를 사용하면, 사용자 머신에 메타스토어 데이터베이스를 만듦
hive 명령어 실행한 위치에 metastore_db 라는 디렉터리 만들어 그 안에 필요한 파일 저장

local 데이터를 읽고 local 에 저장할 수 있음
저장시 데이터를 변경하지 않고 그대로 저장
local 에 저장할 때 하이브가 저장하는 경로는 웨어하우스 디렉터리(기본값 /user/hive/warehouse)

하이브는 특정 테이블 질의할 때 모든 파일을 다 읽음
그래서 효율적인 쿼리를 위해 버켓팅, 파티셔닝이 필요



하이브 속성 설정 우선순위
1. hive> 에 넣는 SET 명령어
2. 명령어에 넣는 -hiveconf 옵션
3. *-site.xml
4. *-default.xml



Hive 쿼리 실행 엔진은 MR, Tez, Spark 를 지원


 

2.


하이브 서비스
- cli : hive 드라이버에 바로 접근. 접근 권한 확인 하지 않아서 되도록 hiveserver2 사용
- hiveserver2 : 다른 언어로 개발된 클라이언트와 연동 가능하도록 하이브 쓰리프트 서비스 실행
  hiveserver2 로 쓰리프트 서비스가 실행되고,
  이를 통해 다른 언어에서 thrift, JDBC, ODBC 연결자로 하이브에 연결 가능
  접근 권한 확인 등을 hiveserver2 에서 진행
- beeline : JDBC 로 hiveserver2 프로세스에 접근하는 명령행 인터페이스
- hwi : 하이브 웹 인터페이스
- 메타스토어 : 기본적으로 메타스토어는 하이브 서비스와 동일한 프로세스에서 실행됨
  이 서비스는 메타스토어를 독립형 원격 프로세스로 실행함

 

 

3.


메타스토어는 하이브 메타데이터를 저장하는 핵심 저장소
메타스토어는 서비스데이터 보관 저장소로 나뉨

내장 메타스토어
- 메타스토어 서비스 : 하이브 서비스와 동일한 JVM 내에서 동작
- 메타스토어 저장소 : 하이브 서비스와 동일한 JVM 내에서 동작. derby
  local 에 데이터 저장하는 derby 데이터베이스
  derby 는 한 번에 db파일 하나에만 접근 가능해서 하나의 하이브 세션만 사용 가능
  (다른 사용자 등에 의해) 두 번째 세션 사용 불가
  따라서 다중 세션(다중 사용자) 지원 불가

로컬 메타스토어
- 메타스토어 서비스 : 하이브 서비스와 동일한 JVM 내에서 동작
- 메타스토어 저장소 : 원격 머신에서 별도의 프로세스로 실행되는 데이터베이스. mysql, postgresql etc
  다중 세션(다중 사용자) 지원 가능
  mysql, postgresql 등을 원격 데이터베이스로 사용

원격 메타스토어
- 메타스토어 서비스 : 하나 이상의 메타스토어 서버가 하이브 서비스와 별도의 JVM 프로세스로 실행
- 메타스토어 저장소 : 원격 머신에서 별도의 프로세스로 실행되는 데이터베이스. mysql, postgresql etc
  클라이언트와 메타스토어 서버는 thrift로 통신함
  데이터베이스 계층이 방화벽 역할을 대신하기 때문에
  클라이언트는 데이터베이스 자격 증명을 얻을 필요가 없어서 관리성과 보안성이 높아진다는데
  무슨 말인지 모르겠음
  메타스토어 서비스가 별도의 서버에서 실행되면, 가용성과 확장성이 제공됨


 

 

4.


rdb 와 hive 차이
- rdb 는 쓰기 스키마, hive 는 읽기 스키마
  쓰기 스키마는 index 를 지원해서 쿼리가 빠르지만,
  읽기 스키마는 디스크 직렬화가 필요없어서 데이터 write 가 매우 빠름
- rdb 의 트랜잭션, 색인 기능은 hive 에서 일부 지원
  트랜잭션(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)가 존재함

stored as : 데이터를 저장하는 파일 포맷 지정
저장 포맷은 TEXTFILE, SEQUENCEFILE, ORC, PARQUET 등이 존재
바이너리인 sequence, orc, parquet 등은 행의 형식이 바이너리 포맷에 따라 결정되므로 row format 지정 불필요

참고 https://wikidocs.net/23469



hive 는 읽기 스키마를 사용하기 때문에
테이블의 이름 변경, 테이블의 정의 변경, 새로운 컬럼 추가 등이 자유로움


 

셔플 조인은 가장 느린 조인

맵(Map) 단계에서 각 테이블을 읽고, 조인 컬럼을 키로 설정하여 셔플

리듀서로 데이터가 이동되고 리듀서에서 테이블을 조인

 

버켓팅 되어있으면 Bucket Map Join 이 빨라짐.

https://data-flair.training/blogs/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 사용

JDBC :

- Java Database Connectivity

- JAVA 언어로 DB 에 접근해 DML 쿼리 하기 위한 인터페이스

- Java와 연동되는 DBMS에 따라 그에 맞는 JDBC를 설치할 필요가 있음

ODBC

- Open Database Connectivity

- 응용프로그램에서 다양한 DB 에 접근해 DML 쿼리하기 위한 인터페이스

- 접속처의 데이터베이스가 어떠한 DBMS에 의해 관리되고 있는지 의식할 필요가 없음

 

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 는 대규모 데이터 레이크에서 테이블을 효율적으로 관리하기 위해 설계된 테이블 포맷
HDFS, S3 등 다양한 스토리지에서 대량의 데이터를 안정적으로 관리하고 빠르게 쿼리할 수 있도록 최적화 됨



Iceberg 의 장점은 다음과 같음
- 대용량 데이터(수십~수백 페타바이트) 처리 최적화
- ACID 트랜잭션 지원 (데이터 일관성 보장)
  (ACID : 원자성(Atomicity), 일관성(Consistency), 격리성(Isolation), 지속성(Durability) )
- Schema Evolution 지원 (스키마 변경 가능)
- Partition Evolution 지원 (파티셔닝 변경 가능)
- Time Travel 지원 (과거 데이터 조회 가능)
- 다양한 엔진(Hive, Spark, Trino, Flink, Presto)과 호환




 

+ Recent posts