정형 데이터 배치를 Sqoop 에서 Spark 으로 전환 후 전체 데이터를 조회 했을 때 아무 문제 없이 조회가 가능했다.
하지만 Spark으로 전환 시점 부터 데이터 조회 시 에러 로그를 보여주며 조회가 되지 않았다.
예를 들어 아래와 같이 전체 조회 시 문제가 없으나
SELECT *
FROM TABLE
아래 처럼 특정 파티션을 조회하면 에러가 발생한다.
SELECT *
FROM TABLE
WHERE PART_BASE_DT = '202306'
그러나 Spark 에서 특정 파티션을 조회하면 정상적으로 조회가 가능하다.
spark.sql("""
SELECT *
FROM TABLE
WHERE PART_BASE_DT = '202306')
특정 파티션 조회 시 아래와 같은 에러가 발생한다.
org.apache.hive.service.cli.HiveSQLException:
java.io.IOException: parquet.io.ParquetDecodingException: Can not read
value at 0 in block -1 in file hdfs
상당히 일리가 있는 말이라고 생각했다. 특히 Spark 에서 INSERT OVERWRITE
구문을 적용하기 어려워 아래와 같이 spark.sql
을 활용하여 스테이지로 올린 데이터를 insert 했다.
spark.sql(f"""
INSERT OVERWRITE LAKE.{TABLE}
SELECT *,
current_timestamp() as HSYS_UPD_DTTM,
substring(base_dt, 1, 6) as PART_BASE_DT
FROM STAG.{TABLE}
""")
역시나 *
을 사용해서 넣다 보니 컬럼 순서가 완벽하게 일치하지 않아 데이터 순서가 바뀐 테이블이 몇 존재했다. 하지만 조회 시 문제의 로그는 발생하지 않았다.
spark.sql
구문을 활용하여 INSERT OVERWRITE
를 진행했을 때 별도의 포맷을 지정하여 저장을 할 수 없었다.
그렇기 때문에 포맷의 문제인지 확인을 위해 먼저 Hive 테이블 스키마 상태를 확인했다.
SHOW CREATE TABLE LAKE.TABLE
역시나 Parquet 포맷으로 지정해 둔 것을 확인할 수 있었지만 한 가지 마음에 걸리는 부분이 있다.
ParquetHiveSerDe
라는 포맷으로 지정 돼 있는 부분이 말이다.
먼저 ParquetHiveSerDe
가 어떤 것인지 구글링 하면 아래와 같은 클래스 소개 페이지가 나온다.
SerDe
라 함은 직렬화(Serialize) 역직렬화(Deserialize)의 합성어로 시스템 간의 데이터를 주고 받을 때의 약속 된 포맷으로 변형해서 보내거나 약속된 포맷에서 데이터를 취하는 것을 말한다.
분명 저 클래스를 활용해야 하는 것이라는 생각이 든다. 그렇다면 Spark 에서 사용하는 Parquet 은 어떤걸까?
"When reading from Hive metastore Parquet tables and writing to non-partitioned Hive metastore Parquet tables, Spark SQL will try to use its own Parquet support instead of Hive SerDe for better performance. This behavior is controlled by the spark.sql.hive.convertMetastoreParquet configuration, and is turned on by default."
위 글을 확인해보면 성능상의 문제로 Spark 에서 제공하는 MetastoreParquet 를 사용한다고 한다.
그렇다면 위에서 본 ParquetDecodingException 은 서로의 테이블과 저장하려는 주체의 포맷 불일치로 보인다.
spark.sql.parquet.writeLegacyFormat
옵션을 활성화 시켜서 데이터를 저장하면 Hive 에서 조회도 문제 없이 가능하다.
"If true, data will be written in a way of Spark 1.4 and earlier. For example, decimal values will be written in Apache Parquet's fixed-length byte array format, which other systems such as Apache Hive and Apache Impala use. If false, the newer format in Parquet will be used. For example, decimals will be written in int-based format. If Parquet output is intended for use with systems that do not support this newer format, set to true."
Document 에서 설명하는 것과 같이 옵션 활성화 시 1.4 버전 이하 방식으로 데이터를 저장한다고 한다.
결국 문제는 Hive 에서 새로운 Parquet 포맷을 지원하지 않아 발생했던 문제였다.