[python] Pyspark local 환경 설정 및 AWS S3 데이터 읽기, Window 환경, Error 해결
오늘은 window 로컬 환경에서 Pyspark를 설정하는 방법을 정리하고자 한다.
사실 S3를 DB 개념으론 써봤지만, AWS Glue script, Step function 등을 활용한 구체적인 ETL 작업까진 경험이 없던지라 데이터 수집 후 스키마 설정 등을 위해 pyspark를 써보게 된 것도 처음이었다. 먼저, test를 위해 로컬 환경에서 pyspark를 사용해보려고 했는데, 진짜 설정이 너무나도 까다로웠다. 수많은 에러를 만나고, 어찌어찌 해결한 과정을 작성해보고자 한다.
결론적으로 말하자면 나의 경우에는, pyspark 하나를 쓰기 위해서 수많은 것들을 다운 받아야 하는데 그 파일들의 버전이 호환되지 않았던 것과 경로 지정의 문제였었다.
우선, 전반적인 파일 설치 과정과 에러들을 하나씩 살펴보자.
1. Java 설치 및 환경 설정
기본적으로 window에서 spark 설치 시 java가 기본적으로 설치되어 있어야 합니다. spark는 Java 기반으로 동작하기 때문에 Java 환경(JVM, JAVA Virtual Machine)이 필요하다. 그러므로 첫 단계로는 java를 설치해야 합니다.
* 나의 경우 24년 12월 기준 아무생각 없이 최신 버전을 받았었다가, 버전들의 호환성 때문에 다시 다운그레이드해서 JAVA 8을 받았다.. (호환되는 걸 바로 찾는다면 문제없지만, 결국 다시 다운그레이드해야 할 수도 있으니 이 점은 유의해주세요.)
1.1 JDK 8 설치
https://www.oracle.com/java/technologies/downloads/#java8-windows
Download the Latest Java LTS Free
Subscribe to Java SE and get the most comprehensive Java support available, with 24/7 global access to the experts.
www.oracle.com
위의 사이트에 로그인을 해주시고, 조금 아래로 스크롤을 내리면 JAVA 8이 있습니다. 거기서 윈도우 버전으로 본인 컴퓨터에 맞게 설치해 주세요.
Installer를 클릭하고 exe 파일을 실행해서 설치를 완료해주세요. 따로 설정할 사항은 없어서 계속 next 누르면서 설치를 해줍니다.
1.2 환경변수 설정
전부 설치를 했으면 환경 변수 설정을 해야 합니다. Window 검색창에 '시스템 환경 변수 편집'이라고 검색 후 '환경 변수'를 눌러주세요. 아래쪽의 시스템 변수에서 새로 만들기를 눌러서 아래와 같이 저장해 주세요.
(보통은 Program Files에 설치가 되던데, 본인의 설치 경로를 따로 확인은 해주세요.)
이렇게, 다 해줬으면 path를 찾아서 "편집"을 클릭하고 새로 만들기를 해서 %JAVA_HOME%\bin을 입력해 주세요.
* 추가적으로 python은 3.10~3.11 버전을 사용했습니다. 3.13 버전은 spark가 안 돌아갔었어요. 혹시라도 높은 버전이라면 가상환경을 사용하시거나, 다운그레이드해주세요.
그리고, 제대로 설치가 됐는지 한번 확인하기 위해서 cmd 창을 켜고 java -version을 입력 후 버전을 확인해 주세요.
이제 처음 한 단계가 끝이 났습니당..
2. Spark 설치 및 환경 변수 설정
2.1 Spark 설치
이제 Spark를 설치해 줄 단계입니다. 저는 spark 3.4.0을 설치했어요.
https://spark.apache.org/downloads.html
Downloads | Apache Spark
Download Apache Spark™ Choose a Spark release: Choose a package type: Download Spark: Verify this release using the and project release KEYS by following these procedures. Note that Spark 3 is pre-built with Scala 2.12 in general and Spark 3.2+ provides
spark.apache.org
노란색으로 표시한 Spark release archives에 들어가서, spark 3.4.0을 눌러주고 tgr.gz 파일을 다운로드합니다.
(시간이 무척 오래걸렸슴다..)
자, 이제 다운로드한 파일을 C:/에 옮겨서 압축을 해제해 주면 폴더가 생성이 됩니다.
* 아마 최신 버전의 spark를 받게 되면 choose a packager type에서 pre-built for Apache Hadoop and later 이걸 선택할 수 있는데, 이걸로 받게 되면 hadoop은 따로 설치를 안 해도 되는 것 같지만, 전 다른 버전을 설치했어서 그냥 hadoop도 따로 받아줬습니다. 이건 아래에서 다시 설명할게요.
2.2 시스템 환경 변수 설정
이제 JDK와 마찬가지로 시스템 환경 변수를 설정해줘야 합니당. 하는 과정은 똑같습니다.
"새로 만들기"를 클릭해서 SPARK_HOME, 설치 경로를 입력하고 확인을 눌러준 후, Path를 찾아서 "편집"을 누르고, % SPARK_HOME%bin\을 입력해 줍니다.
3. Hadoop 설치 및 환경 변수 설정
3.1 Hadoop 설치
앞서, 간략하게 설명했듯 저는 hadoop을 따로 설치해 줬습니다. hadoop의 경우 3.3.1 버전을 설치해줬습니다.
(tmi 지만 처음에 hadoop을 3.0.0을 받았다가 spark와의 호환성 때문에 다시 3.3.1로 받아줬습니당 ^.^ 진쨔 귀찮았다..)
마찬가지로, release archive를 눌러서 hadoop-3.3.1을 눌러서 tar.gz 파일을 다운로드해주세요.
다운로드 후에 C:/에 해당 폴더를 압축 해제 하면 경로가 생깁니다.
3.2 환경 변수 설정
이제 이쯤 되면 지겹죠? 완벽히 같은 방법으로 이번엔 HADOOP_HOME으로 아까 압축 해제한 파일의 경로를 시스템 환경 변수로 등록해 줍니다. 그리고 또 똑같이, path를 찾아서 "편집"을 누른 후 %HADOOP_HOME%\bin을 입력해 줍니다.
* 자, 다시 돌아가서 앞서 spark를 설치할 때, pre-built for Apache Hadoop and later 요거를 설치하면은 hadoop이 알아서 설치가 되어서 굳이 hadoop을 저처럼 따로 다운로드할 필요는 없는 것 같고, 바로 hadoop 버전과 맞는 winutils를 설치해 주면 되는 듯합니다. 하지만, 환경 변수는 똑같이 설정해주어야 합니다. 이렇게 설치하신 경우는 그냥 다음과 같이 해주시면 되는 듯합니다. (틀린 정보일수도 있어요.. 참고참고)
이제 모든 환경 변수 설정을 마쳤으면, 재부팅을 한번 해줍니다.
3.3 추가 환경 설정
다른 블로그들을 참고했을 때 주로 이 세 가지만 환경설정을 하면 된다고 나오지만, 저는 SYSPARK_PYTHON이라는 환경변수도 하나 설정해 줬어요.
(아마도 설치한 파이썬 파일에 대한 시스템 변수가 없어서 이걸 해줘야 spark가 돌아갔던 듯해요.. 다른 분들은 이미 있어서 그럴 수도 있고,, 자세히는 모르겠긴 합니다..)
저의 경우, (C:\Users\ehddl\AppData\Local\Programs\Python\Python313\python.exe) 다음과 같은 폴더에 python이 있어서 해당 경로로 시스템 환경 변수를 설정해 줬고, 마찬가지로 path를 찾아서 "편집"을 누른 다음, %SPARK_HOME%\bin을 입력해 줍니다.
4. jar 파일 설치
이제 끝이면 좋겠지만, 끝난 게 아닙니다. spark는 java 기반이라고 말씀드렸는데, python에서 이걸 활용하려면 java 관련 서비스와 환경 설정을 위한 프레임워크(?)들이 더 필요합니다.
크게 3가지의 jar 파일들이 필요합니다. 여기서부터 자신이 받은 spark와 hadoop이 호환되는 버전의 파일을 잘 선택해서 다운해야 합니다..
4.1 hadoop-aws.jar
https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-aws
저는 spark-3.4.0, hadoop-3.3.1 버전을 다운로드하였기 때문에 hadoop-aws.jar는 3.3.1 버전을 다운로드하여줬습니다.
설치할 버전을 눌러주면, 다음 페이지로 넘어가는데 jar 파일을 받아주면 됩니다.
4.2 AWS SDK for JAVA Bundle (aws-java-bundle.jar)
https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-bundle
다음으로는 aws-java-bundle-1.12.180.jar를 받아줬습니다. 마찬가지로 특정 버전을 눌러서 jar 파일을 다운로드해줍니다.
4.3 Apache HttpClient (httpclient.jar)
https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient
다음은 httpclient-4.5.13.jar를 받아주었습니다.
자, 이렇게 세 가지의 jar 파일들을 다운로드하여주었으면 이 파일들을 한 곳으로 옮겨줘야 하는데,
설치한 spark 파일로 이동하면 (C드라이브의 spark 파일 경로) jar 파일이 있습니다. 그곳에 다운로드한 세 가지의 jar 파일들을 옮겨줍니다.
(아마 이걸 cmd나 코드단에서 경로를 직접 설정해줄 수 있지만, 저는그냥 이렇게 옮겨줬습니다.)
5. hadoop core-site 편집
이제 마지막! 설치한 hadoop 안에는 core-site라는 게 있는데, 이걸 직접 설정을 해줍니다.
저는 다음과 같은 경로였습니다. "C:/hadoop-3.3.1/etc/hadoop/core-site"
(이것 또한 core-site 편집하지 않고, 바로 python에서 코드단에서 pyspark 설정에서 해보았지만, 해당 스크립트를 따로 수정하지 않으니까 javaLang 에러가 계속 나더라구요..그래서 전 그냥 해당 부분을 직접 수정해주었습니다.)
다음과 같이 수정해 줍니다.
<configuration>
<property>
<name>fs.s3a.access.key</name>
<value>YOUR_ACCESS_KEY</value> # 본인의 s3 access_key
</property>
<property>
<name>fs.s3a.secret.key</name>
<value>YOUR_SECRET_KEY</value> # 본인의 s3 secret_key
</property>
<property>
<name>fs.s3a.endpoint</name>
<value>s3.ap-northeast-2.amazonaws.com</value>
</property>
<property>
<name>fs.s3a.path.style.access</name>
<value>true</value>
</property>
<property>
<name>fs.s3a.impl</name>
<value>org.apache.hadoop.fs.s3a.S3AFileSystem</value>
</property>
</configuration>
자, 그리고 이제 다시 한번 재부팅을 하고 나서 cmd 창을 켜고 pyspark를 입력해 주세요.
spark 글자와 version 정보가 뜬다면 설치 성공입니당.
6. python 실행 pyspark code
자, 일단 전부 설치를 마쳤으니 pip install pyspark를 진행해 주세요.
그리고 이제 aws s3 접근을 위한 spark 설정을 하는 방법을 알려드리겠습니다.
저의 경우에는 accesskey를 .env 파일에 저장하고 불러왔기 때문에, load_dotenv를 했는데, 다이렉트로 사용하실 분은 그냥 바로 본인의 키를 바로 작성해 주세요. (다만, 보안상 문제 때문에 권장하진 않습니다.)
from pyspark.sql import SparkSession
from pyspark import SparkConf, SparkContext
from dotenv import load_dotenv
# 기존 SparkContext가 있다면 종료
if SparkContext._active_spark_context is not None:
SparkContext._active_spark_context.stop()
load_dotenv()
aws_access_key = os.getenv("aws_accessKey")
aws_secret_key = os.getenv("aws_secretKey")
conf = SparkConf()
conf.set("spark.hadoop.fs.s3a.endpoint", "s3.ap-northeast-2.amazonaws.com") # seoul region
conf.set("spark.hadoop.fs.s3a.access.key", aws_access_key) # 본인의 access_key
conf.set("spark.hadoop.fs.s3a.secret.key", aws_secret_key) # 본인의 access_key
conf.set("fs.s3a.impl", "org.apache.hadoop.fs.s3a.S3AFileSystem")
conf.set("spark.hadoop.fs.s3a.path.style.access", "true")
conf.set("spark.hadoop.fs.s3a.connection.ssl.enabled", "true")
spark = SparkSession.builder \
.config(conf=conf) \
.appName("example") \
.getOrCreate()
# Signature V4 설정
spark.sparkContext.setSystemProperty("com.amazonaws.services.s3.enableV4", "true")
자. 이렇게 작성하는 게, 사실 기본적인 설정인 듯합니다.
그런데 이렇게 해서 딱 되면 ㄹㅇ 환상적일 텐데, 저는 ;; 바아로 에러가 났습니다. ㅎㅋㅌㅎㅎㅋ
6.1 S3AFileSystem not found error
"S3AFileSystem not found error"라는 error가 날 수 있습니다.
이걸 해결하기 위해서 앞서 수많은 jar 파일들을 받은 거랍니다. 이제 그 파일의 경로를 conf에 집어넣어줄 겁니다.
근데, 이제 본인의 spark 폴더에 들어가서 jar 파일이 들어있는 경로를 넣어주셔야 합니다!!!
conf = SparkConf()
conf.set("spark.hadoop.fs.s3a.endpoint", "s3.ap-northeast-2.amazonaws.com")
conf.set("spark.hadoop.fs.s3a.access.key", aws_access_key)
conf.set("spark.hadoop.fs.s3a.secret.key", aws_secret_key)
conf.set("fs.s3a.impl", "org.apache.hadoop.fs.s3a.S3AFileSystem")
conf.set("spark.hadoop.fs.s3a.path.style.access", "true")
conf.set("spark.hadoop.fs.s3a.connection.ssl.enabled", "true")
# S3AFileSystem not found error -> 해당 error 발생 시 여기 부분 추가
conf.setAll([('spark.driver.extraClassPath', '/spark-3.4.0-bin-hadoop3/jars/aws-java-sdk-bundle-1.12.180.jar:/spark-3.4.0-bin-hadoop3/jars/hadoop-aws-3.3.1.jar')])
spark = SparkSession.builder \
.config(conf=conf) \
.appName("example") \
.getOrCreate()
# Signature V4 설정
spark.sparkContext.setSystemProperty("com.amazonaws.services.s3.enableV4", "true")
그럼 이제 된다구요? 그럼 다행입니다. 하지만 또 error가 날 겁니다 ㅎㅋㅎㅋ
6.2 IAMInstanceCredentialsProvider not found error
conf = SparkConf()
conf.set("spark.hadoop.fs.s3a.endpoint", "s3.ap-northeast-2.amazonaws.com")
conf.set("spark.hadoop.fs.s3a.access.key", aws_access_key)
conf.set("spark.hadoop.fs.s3a.secret.key", aws_secret_key)
conf.set("fs.s3a.impl", "org.apache.hadoop.fs.s3a.S3AFileSystem")
conf.set("spark.hadoop.fs.s3a.path.style.access", "true")
conf.set("spark.hadoop.fs.s3a.connection.ssl.enabled", "true")
# S3AFileSystem not found error
conf.setAll([('spark.driver.extraClassPath', '/spark-3.4.0-bin-hadoop3/jars/aws-java-sdk-bundle-1.12.180.jar:/spark-3.4.0-bin-hadoop3/jars/hadoop-aws-3.3.1.jar')])
# IAMInstanceCredentialsProvider not found error
conf.set("spark.hadoop.fs.s3a.aws.credentials.provider", "org.apache.hadoop.fs.s3a.SimpleAWSCredentialsProvider")
spark = SparkSession.builder \
.config(conf=conf) \
.appName("example") \
.getOrCreate()
# Signature V4 설정
spark.sparkContext.setSystemProperty("com.amazonaws.services.s3.enableV4", "true")
해당 에러가 발생하면, 저런 코드를 또 추가해 줍니다..ㅎㅎ
다행히, 저는 여기서 문제가 해결이 되었습니다.
그런데, 아마 여기서 끝나지 않으실 수도 있습니다.
(저도 정리하고 정리하다 보니 이런 결론이 난거지 수많은 error를 여러 가지 순서로 맛보긴 했습니다.)
만약에 Py4JJavaError가 뜨면서, 403 Fobidden 이런 게 뜬다면 아마 s3 접근 권한이 없다는 것이거나,
앞서 jar 파일이나, 다운로드한 spark, hadoop 파일들의 버전 호환성 문제일 수도 있습니다.
* 참고로, 저도 여러 가지 블로그와 gpt를 참고하면서 conf.setAll로 해결하긴 했는데,
처음에는 다른 코드와 동일하게 conf.set을 활용해서 다음과 같은 코드로 실행했거든요.
# conf.set("spark.jars.packages", "org.apache.hadoop:hadoop-aws:3.3.1,com.amazonaws:aws-java-sdk-bundle:1.12.180)
근데 전 이렇게 해도 Py4JJavaError와 S3AFileSystem not found error이 번갈아가면서 나왔습니다^.^
저의 경우는 S3AFileSystem not found error 때문에 설정한 conf에 jar 파일들의 경로를 제대로 넣어주지 못해서 일어난 error 였습니다..이걸 수정해 주니 바로 돌아가더라고요. 그래서 이 부분 잘 챙겨주세요!
6.3 최종 코드
그래서, 정리하자면 최종 코드는 아래와 같습니다.
from pyspark.sql import SparkSession
from pyspark import SparkConf, SparkContext
from dotenv import load_dotenv
# 기존 SparkContext가 있다면 종료
if SparkContext._active_spark_context is not None:
SparkContext._active_spark_context.stop()
load_dotenv()
aws_access_key = os.getenv("aws_accessKey")
aws_secret_key = os.getenv("aws_secretKey")
conf = SparkConf()
conf.set("spark.hadoop.fs.s3a.endpoint", "s3.ap-northeast-2.amazonaws.com")
conf.set("spark.hadoop.fs.s3a.access.key", aws_access_key)
conf.set("spark.hadoop.fs.s3a.secret.key", aws_secret_key)
conf.set("fs.s3a.impl", "org.apache.hadoop.fs.s3a.S3AFileSystem")
conf.set("spark.hadoop.fs.s3a.path.style.access", "true")
conf.set("spark.hadoop.fs.s3a.connection.ssl.enabled", "true")
# S3AFileSystem not found error
conf.setAll([('spark.driver.extraClassPath', '/spark-3.4.0-bin-hadoop3/jars/aws-java-sdk-bundle-1.12.180.jar:/spark-3.4.0-bin-hadoop3/jars/hadoop-aws-3.3.1.jar')])
# IAMInstanceCredentialsProvider not found error
# conf.set("spark.hadoop.fs.s3a.aws.credentials.provider", "org.apache.fs.s3a.SimpleAWSCredentialsProvider")
conf.set("spark.hadoop.fs.s3a.aws.credentials.provider", "org.apache.hadoop.fs.s3a.SimpleAWSCredentialsProvider")
spark = SparkSession.builder \
.config(conf=conf) \
.appName("example") \
.getOrCreate()
# Signature V4 설정
spark.sparkContext.setSystemProperty("com.amazonaws.services.s3.enableV4", "true")
이제 읽고 싶은 파일을 로딩하면 됩니다.
# Example: S3 경로 확인
df = spark.read.csv("s3a://your-bucket-name/your-folder/your-file.csv", header=True, inferSchema=True)
이렇게 해서 무사히 spark session 설정을 마쳤습니다... 정말 길고 긴 과정이었습니다.
에러 코드를 조금만 더 신중히 살펴보고 경로를 잘 확인했더라면 이렇게 오래걸리지 않았을 문제였겠지만, 문제를 정확히 쳐다보지 못해서 시간을 조금 버렸었네요ㅜ..이렇게 또 하나를 배웠습니다.
부디 이 글이 pyspark를 사용하려다 error에 부딫힌분들께 도움이 되면 좋겠습니다.
오늘도 얼렁뚱땅 신입 AI Engineer의 글이었습니댱.
감사합니다.