如何在AWS EMR集群上安装符合应用需求的指定Spark版本?
EMR 6.0(原生集成HBase 2.2.3)下部署匹配需求的Spark 2.4.x(Scala 2.11)的最佳方案
首先明确EMR 6.0的原生基线:该版本默认预装Spark 3.0.1(Scala 2.12构建),如果直接修改替换原生Spark路径,会连带破坏EMR控制台作业监控、作业历史服务、EMR Studio联动、引导脚本适配等平台能力,因此最佳方案核心原则是用户态完全隔离自定义Spark运行时,不改动集群原生组件。
具体实施步骤
- 前置依赖梳理
- 全程保留EMR原生安装路径
/usr/lib/spark、/usr/lib/hbase的所有文件、权限、全局环境变量配置,平台侧的所有能力继续基于这套原生组件运行,不做任何覆盖升级操作 - 在所有集群节点创建独立的自定义Spark部署目录,比如
/opt/spark-custom-2.4.8,可通过EMR引导动作完成目录初始化和文件同步,不要用网络挂载存储作为Spark的部署路径,避免运行时IO抖动
- 全程保留EMR原生安装路径
- 定制符合要求的Spark安装包
- 选择和应用编译时完全一致的Spark 2.4.x小版本,下载官方发布的Scala 2.11构建变体安装包,绝对禁止使用Scala 2.12构建的Spark包,否则会出现Scala二进制不兼容导致的类加载异常
- 移除安装包内自带的版本不匹配的HBase相关依赖(hbase-client、hbase-common、hbase-spark等所有和HBase相关的jar包),运行时直接复用节点上原生的HBase 2.2.3客户端,避免RPC协议、类加载顺序冲突
- 若需要Spark对HBase的读写支持,直接从节点的
/usr/lib/hbase路径复用对应版本的hbase-spark连接器jar,不要自行引入其他第三方版本的连接器
- 环境隔离配置
- 不修改全局
/etc/environment中的SPARK_HOME配置,避免覆盖原生Spark的路径变量导致平台功能异常 - 运行自定义Spark版本的作业时,临时设置独立环境变量:提交作业前执行
export SPARK_HOME=/opt/spark-custom-2.4.8,强制使用该目录下的spark-submit提交作业 - 作业提交时通过参数指定类路径:
spark.driver.extraClassPath=/usr/lib/hbase/*、spark.executor.extraClassPath=/usr/lib/hbase/*,让Spark运行时直接加载原生HBase客户端依赖 - 配置
spark.yarn.jars参数指向自定义Spark目录下的jar包路径,或者提前将jar包上传到HDFS的固定路径,减少作业提交时的重复上传开销
- 不修改全局
- 兼容性验证
- 跑通最小验证链路:提交一个简单的Spark读取HBase表的测试作业,确认无
ClassNotFoundException、NoSuchMethodError类依赖冲突 - 验证Scala运行时版本:在测试作业中打印Scala当前运行时版本,确认匹配应用要求的2.11.x版本
- 确认YARN侧作业监控正常:由于自定义Spark运行时仍然跑在集群原生YARN资源管理器上,只要资源调度参数配置正确,EMR控制台的作业监控、资源统计不会出现异常
- 跑通最小验证链路:提交一个简单的Spark读取HBase表的测试作业,确认无
明确不推荐的错误操作
- 不要直接覆盖
/usr/lib/spark下的原生文件:不仅会破坏EMR平台的关联功能,后续EMR的集群维护操作还会自动恢复原生文件,导致作业随机失败 - 不要依赖运行时动态拉取Spark或HBase依赖:很多生产集群无公网访问权限,在线拉取依赖会直接超时,且拉取到的依赖版本和集群HBase 2.2.3大概率不兼容
- 不要在自定义Spark包内全量打包所有HBase依赖:多个版本的HBase jar包共存会出现类加载顺序错乱,导致HBase连接随机失败
内容的提问来源于stack exchange,提问作者Oded
相关产品推荐
相关产品推荐

