Spark 에서 외부데이터를 불러와 처리할 때 코드 상에 SparkContext.addFile
메소드를 호출하거나, spark-submit시 --files
파라미터를 이용하여 외부데이터를 읽어와 처리할 수 있다.
이때 두가지 방법이 서로 동작하는 방식이 달라 YARN에 cluster 모드로 실행시 파일을 읽는 방법이 달라지는데, 이에 대해 정리해보고자 한다.
SparkContext.addFile
공식 문서에 따르면 local file, HDFS 뿐 아니라 HTTP, HTTPS, FTP까지 지정하여 사용할 수 있다고 한다.
//add file
SparkSession spark = SparkSession.builder().getOrCreate();
spark.sparkContext().addFile("http://web-server.com/data.txt")
이후 YARN에 클러스터 모드로 배포를 진행해 보면 아래와 같은 로그를 확인할 수 있다.
21/06/25 10:21:09 INFO SparkContext: Added file http://web-server.com/data.txt at http://web-server.com/data.txt with timestamp 1624584069834
21/06/25 10:21:11 INFO Utils: Fetching http://web-server.com/data.txt to /yarn/nm/usercache/testuser/appcache/application_1598512664183_1145336/spark-15af8634-15e9-4c67-9927-1b977d8f21c9/userFiles-8833bd9e-3da4-415e-af08-4ee1a756f5cd/fetchFileTemp3381803683049498493.tmp
즉 data.txt 파일이 Driver가 실행된 서버의 appcache에 다운로드 되는것을 확인할 수 있다.
이렇게 디스크에 저장된 파일을 읽으려면
SparkSession spark = SparkSession.builder().getOrCreate();
spark.sparkContext().addFile("http://web-server.com/data.txt");
spark.read().json("file:///" + SparkFiles.get("data.txt")).show(100);
예제와 같이 file:///
prefix를 붙이고, SparkFiles 클래스를 이용하여 파일명만 지정하게 되면 해당 파일이 존재하는 위치의 Path가 출력되어 파일을 읽을 수 있게 된다.
--files
spark-submit -h를 이용하여 --files의 역할에 대해 간단히 확인해보았다.
--files FILES Comma-separated list of files to be placed in the working
directory of each executor. File paths of these files
in executors can be accessed via SparkFiles.get(fileName).
Comma(,)로 여러개의 파일을 지정할 수 있으며 각 익스큐터는 SparkFiles.get을 이용하여 파일에 접근할 수 있다고 되어있다.
그런데 실제로 SparkFiles.get을 이용하여 파일에 접근하려면 local 모드로 spark잡이 수행되는 경우에만 가능하고, cluster 모드로 수행되는 경우 SparkFiles.get 을 이용할 수 없다.
아래는 spark-submit 을 통해 YARN에 Cluster 모드로 수행될때 남겨지는 로그이다.
21/06/25 10:21:01 INFO ApplicationMaster:
===============================================================================
YARN executor launch context:
YARN executor launch context:
env:
CLASSPATH -> ...
SPARK_YARN_STAGING_DIR -> ..
SPARK_USER -> ..
..중략..
resources:
data.txt -> resource { scheme: "hdfs" host: "hadoop" port: -1 file: "/user/testuser/.sparkStaging/application_1598512664183_1145677/data.txt" } size: 163292 timestamp: 1624594986993 type: FILE visibility: PRIVATE
로그에서 보는것과 같이 data.txt 파일이 spark잡을 수행하는 유저의 .sparkStaging hdfs에 업로드 되는것이 확인되었다.
즉 SparkContext.addFile로 지정된 파일을 읽을때 로컬디스크에서 읽었기 때문에 file:///
prefix를 붙인 반면, --files 를 이용해 파일을 지정한 경우 hdfs의 경로를 입력해 주면 된다.
## spark submit 실행
spark-submit --master yarn --deploy-mode cluster ..생략.. --files http://web-server.com/data.txt ..생략..
으로 실행했을 때 data.txt를 읽으려면 아래와 같이 처리하면 된다.
SparkSession spark = SparkSession.builder().getOrCreate();
//System.getenv("SPARK_YARN_STAGING_DIR") 를 통해 .sparkStaging 경로를 찾아낼 수 있다.
spark.read().json(System.getenv("SPARK_YARN_STAGING_DIR") + "/data.txt").show(100)
--files 를 이용해 파일을 업로드 하게 되면 hdfs의 .sparkStaging/{Application Id} 경로에 업로드 되게 되는데, 이 경로는 어플리케이션이 수행될때마다 변경이 됨으로 System.getenv("SPARK_YARN_STAGING_DIR")
를 통해 현재 동작중인 어플리케이션의 sparkStaging 경로를 찾아 낸 뒤 파일명과 조합하여 사용하면 된다.
추가내용
Spark에서 addFile 또는 --files로 파일을 추가할 때 파일명은 가장 마지막 '/' 부터 마지막까지 문자열을 파일명으로 하게된다.
http://web-server.com/user-data?age=30 -> user-data?age=30 란 이름으로 저장된다.
이때 파일명에 alias를 주고 싶으면 #원하는파일명 으로 선언하면 된다.
spark-submit .. --files=http://web-server.com/user-data?age=30#user-data.txt
'OpenSource > Spark' 카테고리의 다른 글
[Spark Streaming] Streaming 처리시 Offset을 저장해보자. (0) | 2021.04.15 |
---|---|
[Spark Streaming] Kafka를 이용한 스트리밍 처리 시 메세지 중복되는 이유 (0) | 2020.10.07 |
[Spark] HDFS 하위 경로의 모든 파일 읽기(with Java) (0) | 2020.04.27 |