Kerberos 가 켜진 CDP 클러스터에서, Kerberos 가 없는(SIMPLE 인증) 레거시 Hadoop 클러스터의 Parquet 파일을 읽어 CDP 의 Hive 외부 테이블과 Kudu 테이블로 적재한 작업의 기록이다. RPC(hdfs://host:9000) distcp 는 한쪽만 Kerberos 인 상태에서 핸드셰이크가 실패하므로 WebHDFS 로 소스를 읽고, 적재는 spark3-submit 스크립트로 테이블별로 나눠 실행했다. Hive 파티션 테이블 세 개와 Kudu 테이블 세 개, 총 여섯 개를 옮겼다.
/etc/hosts 에 등록한다. WebHDFS 는 NameNode 가 DataNode 호스트명으로 리다이렉트하므로 DataNode 이름이 해석되지 않으면 파일 하나도 못 받는다.for h in mn1 sn1 sn2 sn3; do printf '%s -> ' "$h"; getent hosts $h.<legacy-domain> | awk '{print $1}'; done
curl -sL "http://<src-nn>:50070/webhdfs/v1/<path>/part-00000.snappy.parquet?op=OPEN" -o /tmp/test.parquet
CDP 클라이언트는 Kerberos 로만 통신하도록 잠겨 있어 SIMPLE 서버가 폴백을 요구하면 거부한다. 두 가지 conf 를 Spark 에 주면 소스를 읽을 수 있다. fallback-to-simple-auth-allowed 는 보안을 낮추는 값이므로 이관 작업 셸에서만 export 해서 쓰고 클러스터 설정에는 넣지 않는다.
export SRC_HOST="<src-nn-host>"
export SPARK_CONF="--conf spark.hadoop.dfs.http.policy=HTTP_AND_HTTPS --conf spark.hadoop.ipc.client.fallback-to-simple-auth-allowed=true"
distcp 로 통째로 복사할 때도 같은 원리로 webhdfs:// 소스를 쓰면 RPC 인증 충돌을 피한다.
kinit <user>
hadoop distcp webhdfs://<src-nn>:50070/<src-path> hdfs:///staging/<table>/<ymd>/KR
테이블마다 스크립트를 따로 두고 --ymd 로 소스 경로 일자를 준다. Hive 외부 테이블(Parquet)은 동적 파티션 INSERT OVERWRITE 로 이번 배치에 등장한 파티션만 덮어쓰고, Kudu 는 kudu-spark3 커넥터로 kudu.operation=upsert 를 써서 impala-shell 없이 한 번에 넣는다. 커넥터 JAR 은 parcel 에서 찾는다.
find /opt/cloudera/parcels -name "*kudu-spark*"
spark3-submit --master yarn $SPARK_CONF migrate_login_hist.py --ymd 20250701 --regions KR,EU,US
spark3-submit --master yarn $SPARK_CONF migrate_apt_data.py --ymd 20250701
기간 반복은 셸 루프로 돌리고 nohup 으로 남긴다.
for d in $(seq 0 5); do ymd=$(date -d "20260706 +${d} day" +%Y%m%d); spark3-submit --master yarn $SPARK_CONF migrate_login_hist_ts.py --ymd $ymd --regions KR,EU,US; done
검증은 파티션별 건수 대조로 한다.
SELECT part_ymd, regn_cd, COUNT(*) AS cnt FROM silver.<table> WHERE part_ymd = '20250701' GROUP BY part_ymd, regn_cd ORDER BY regn_cd;
external.table.purge=TRUE 인 외부 테이블은 파티션 DROP 이 HDFS 파일까지 지우므로 파일을 직접 hdfs dfs -rm 하지 않고 DROP PARTITION 으로 정리한다. Impala 에서 했다면 INVALIDATE METADATA 를 잊지 않는다.
ALTER TABLE bronze.<table> DROP IF EXISTS PARTITION (part_ymd='20250701');
INVALIDATE METADATA bronze.<table>;
login_ts 날짜 +1 일)이 있으면 한 경로의 데이터가 여러 파티션으로 갈리므로 동적 파티션 덮어쓰기와 경계일 겹침 확인이 필요하다. 타임스탬프가 비거나 파싱이 안 되는 행은 제외하고 건수를 로그로 남긴다.SHOW PARTITIONS 로 누락을 확인한다.StandbyException: Operation category READ is not supported in state standby 가 보이면 HA NameNode 의 standby 를 먼저 찔러 본 것이라 오류가 아니다.