在AWS EMR集群的PySpark应用中安装s3fs依赖遇阻求助
看起来你在AWS EMR集群上部署依赖s3fs的PySpark应用时遇到了导入错误,我来帮你分析根源并提供几个可行的解决方案:
错误根源分析
你遇到的ImportError: cannot import name raise_from是因为raise_from是Python 3.3及以上版本才内置的语法,而EMR集群默认使用的Python 2.7环境中并没有这个方法。s3fs 0.2.2(或它的底层依赖包)在代码中使用了这个特性,导致在Python 2.7环境下无法正常导入。
方案1:打包兼容依赖包(快速临时解决)
我们可以给s3fs搭配future包(这个包提供Python 2.7对Python 3特性的兼容支持),一起打包成zip文件(EMR对zip的兼容性比egg更好):
- 本地打包依赖:
# 创建临时目录存放依赖 mkdir s3fs_with_deps && cd s3fs_with_deps # 安装s3fs 0.2.2和future到本地目录 pip install s3fs==0.2.2 future -t . # 打包成zip文件 zip -r s3fs_deps.zip . # 上传到你的S3存储路径 aws s3 cp s3fs_deps.zip s3://myBucket/prefix/pkg/
- 启动PySpark时传入这个zip包:
pyspark --py-files s3://myBucket/prefix/pkg/s3fs_deps.zip
此时future包会自动为Python 2.7提供raise_from的兼容实现,解决导入错误。
方案2:用EMR Bootstrap动作预安装依赖(长期集群推荐)
如果不想每次启动PySpark都手动指定依赖包,可以用EMR的Bootstrap动作在集群启动时自动安装s3fs和依赖:
- 创建一个Shell脚本(比如
install_s3fs.sh):
#!/bin/bash # 安装s3fs和兼容依赖 sudo pip install s3fs==0.2.2 future
- 将脚本上传到S3:
aws s3 cp install_s3fs.sh s3://myBucket/prefix/bootstrap/
- 创建EMR集群时添加该Bootstrap动作:
- 控制台方式:在创建集群的“Bootstrap actions”步骤中,选择“Custom action”,指定脚本路径
s3://myBucket/prefix/bootstrap/install_s3fs.sh。 - CLI方式:
aws emr create-cluster \ --name "EMR Cluster with s3fs" \ --release-label emr-5.36.0 \ --applications Name=Spark \ --ec2-attributes InstanceType=m5.xlarge,InstanceCount=3 \ --bootstrap-actions Path=s3://myBucket/prefix/bootstrap/install_s3fs.sh \ --use-default-roles
集群启动后,所有节点都会自动安装好依赖,PySpark可以直接import s3fs使用。
方案3:切换到Python 3环境(彻底解决版本兼容问题)
如果你的业务允许,建议将EMR集群的PySpark切换到Python 3环境,这样就不会遇到Python 2.7的特性缺失问题:
- 临时启动Python 3版PySpark:
# 确保你打包的是Python 3版本的s3fs包,或者直接用下面的方案4 pyspark --conf spark.pyspark.python=python3 --packages s3fs==0.2.2
- 配置集群默认使用Python 3:
用CLI创建集群时添加配置:
aws emr create-cluster \ --name "PySpark Python 3 Cluster" \ --release-label emr-6.8.0 \ --applications Name=Spark \ --configurations '[{"Classification": "spark-env", "Properties": {}, "Configurations": [{"Classification": "export", "Properties": {"PYSPARK_PYTHON": "/usr/bin/python3"}}]}]' \ --ec2-attributes InstanceType=m5.xlarge,InstanceCount=3 \ --use-default-roles
方案4:直接使用Spark的--packages参数(最简便)
EMR的PySpark支持直接通过--packages参数从PyPI拉取依赖包,无需手动打包上传,这是最推荐的方式:
# 启动PySpark时直接指定s3fs版本 pyspark --packages s3fs==0.2.2
或者在提交Spark作业时使用:
spark-submit --packages s3fs==0.2.2 your_spark_application.py
Spark会自动下载s3fs及其所有依赖,分发到集群的所有节点。如果集群没有外网访问权限,只需额外添加--repositories参数指定内部PyPI镜像地址即可。
内容的提问来源于stack exchange,提问作者Bjay

