Hive Metastore 구축 관련 문제와 해결과정

최근 Hive Metastore를 구축하면서 겪은 이슈와 해결과정을 기록해두려고 합니다. 사용 환경은 Spark 2.1.1, Hive 2.1.1 입니다.

Hive Partition

CREATE EXTERNAL TABLE table_name (
col1 STRING,
col2 STRING
)
PARTITIONED BY (key STRING)
STORED AS PARQUET
LOCATION 'location';

Hive에서 보통 위와 같은 쿼리로 테이블을 생성합니다. Metastore는 말 그대로 외부에 있는 테이블의 정보(스키마, 파티션 등)를 저장하는 개념입니다. 따라서 EXTERNAL TABLE 로 생성하지 않은 상태에서 테이블을 DROP 시키면 다 날아가게 됩니다.

ALTER TABLE table_name
ADD PARTITION (key='2017-08-11');

도중에 Partition key를 추가하고 싶을 때는 위와 같은 쿼리를 통해 추가할 수 있습니다. 그러나, 추가한 정보가 바로 반영이 안될 때가 있습니다.

이 경우에는 MSCK REPAIR TABLE table_name; 쿼리로 해결할 수 있습니다. MSCK는 Metastore Check의 약자라고 합니다.

Hive Metastore, Parquet

먼저 겪었던 문제에 대해 설명드리자면 Hive Metastore에 분명히 테이블이 들어가있고, Hue에서는 잘 보이는데 Zeppelin에서는 모든 데이터에 null 값이 찍혀있었습니다.

우선 Spark으로 Hive를 사용하는 방식이 2.0 버전 이후 부터 조금 변경되었습니다. 이전에는 HiveContext를 사용했다면, 이제 SparkSession에서 .enableHiveSupport() 추가만 하면 됩니다. 제플린에서는 SparkSession이 spark이라는 변수로 제공되는데, 이 경우 interpreter에 zeppelin.spark.useHiveContext=true를 추가해서 사용할 수 있습니다.

다시 문제로 돌아와서 좀 더 확인해보니 컬럼명에 대문자가 들어가면 모든 값이 null로 출력되고 있었습니다. Spark 공식문서에 이와 관련된 내용이 잘 나와있습니다.

Spark SQL에서 Hive metastore로 데이터를 불러오는 경우, 성능 상의 이슈로 SerDe 대신 Spark SQL의 MetastoreParquet 를 사용합니다. 이때 주의사항으로 Hive는 대소문자를 구분하지 않지만, Parquet는 구분합니다. (Hive is case insensitive, while Parquet is not)

이를 위해 Spark 2.1.1 버전부터 새로운 Spark Properties가 추가되었습니다.

따라서, Zeppelin interpreter에 아래의 설정 값을 추가해주시면 해결됩니다. spark.sql.hive.caseSensitiveInferenceMode = INFER_AND_SAVE

Hive TBLPROPERTIES

위에서 말한대로 Spark Properties를 추가하면, Hive metastore의 parameter에 spark.sql.sources.schema.part가 생기게 됩니다.

여기에서 “field: name”에 대소문자가 잘 구분되는 경우, 문제가 없지만 간혹 소문자로 들어오는 경우가 있습니다. 이 경우에는 아래의 쿼리를 통해 Hive parameter를 수정해주시면 됩니다.

ALTER TABLE table_name SET TBLPROPERTIES ("spark.sql.sources.schema.part.0" = "fix this line");

Reference