首页 / 资讯中心 / 文章详情

Windows上搭建Spark本地开发环境:IDEA 2020.1 + Maven + Scala实战

Windows上搭建Spark本地开发环境:IDEA 2020.1 + Maven + Scala实战 ★ FEATURED ARTICLE
1. 为什么在Windows上折腾Spark开发环境值得认真对待大数据生态里Spark 的本地开发环境搭建一直是新手最容易卡住的第一道坎。很多人以为装个 IDEA 就完事了结果被 Scala 版本、Maven 依赖、JDK 兼容性、Hadoop 工具包这几座大山轮番教育。我自己前前后后在不同机器上搭过不下十次这套环境从最早被NoClassDefFoundError折磨到凌晨到后来能在二十分钟内从零跑通一个 WordCount中间踩的坑基本能写一本小册子。这篇内容面向的是想在 Windows 上跑通 Spark 本地开发的同学尤其是用Intellij IDEA 2020.1 社区版 Maven 3.6.3 Scala 2.11.8这套组合的人。为什么强调这三个版本因为 IDEA 2020.1 是很多老项目还在用的稳定版本社区版免费且够用Maven 3.6.3 是 3.6.x 系列里兼容性口碑最好的一个Scala 2.11.8 则是 Spark 2.x 时代最主流的编译版本大量生产环境的 Spark 项目至今仍锁死在这个版本上。你如果直接上 Scala 2.12 或 2.13会遇到一堆二进制不兼容的问题编译期报错能让你怀疑人生。我会把整套流程拆成环境准备、依赖配置、代码编写、运行调试、问题排查几个部分每一步都告诉你为什么这么做、参数怎么算、哪里容易翻车。不管你是刚接触 Spark 的新手还是换机器重新搭环境的老手照着走一遍应该能少走不少弯路。2. 环境整体设计与版本选型逻辑2.1 为什么是这套版本组合先说说版本这件事因为它决定了后面 80% 的坑会不会出现。Spark 的版本和 Scala 版本是强绑定的Spark 2.4.x 官方编译默认用的是 Scala 2.11.12但 2.11.8 和 2.11.12 在二进制层面是兼容的所以用 2.11.8 没问题。真正要命的是跨大版本比如你项目里写 Scala 2.12 的代码去调 Spark 2.4 的 jar 包运行时会直接抛NoSuchMethodError因为 Scala 2.12 和 2.11 的集合库、函数签名都不一样。JDK 这边Spark 2.x 官方推荐 JDK 8。JDK 11 虽然也能跑但会遇到一些反射相关的警告甚至报错尤其是和sun.misc.Unsafe相关的调用。所以稳妥起见JDK 8是唯一推荐选项。Maven 3.6.3 相比 3.5.x 改进了依赖解析的并发处理相比 3.8.x 又不会强制要求 HTTPS 仓库对国内网络环境更友好。IDEA 2020.1 社区版有个好处是它对 Scala 插件的兼容性比较稳定。新版 IDEA 有时候 Scala 插件更新跟不上会出现代码提示失效、编译卡死的情况。2020.1 这个版本配上对应时期的 Scala 插件用起来很顺。2.2 整体架构思路这套环境的核心思路是用 Maven 管理依赖用 Scala 写代码在 IDEA 里以本地模式运行 Spark。本地模式意味着不需要搭 Hadoop 集群Spark 会用本地线程模拟分布式计算适合开发和调试。Maven 负责把 Spark 的核心 jar 包、Scala 库、Hadoop 客户端依赖全部拉下来IDEA 负责提供代码编辑和运行入口。这里有个关键点Spark 依赖里会间接引入 Hadoop 的库但 Windows 上缺少 Hadoop 的本地库比如winutils.exe和hadoop.dll如果不处理运行时会报Could not locate executable null\bin\winutils.exe。这个问题的解决方案后面会详细讲。整个环境的目录结构建议这样规划一个统一的开发目录比如D:\dev下面分jdk、maven、scala、hadoop、workspace几个子目录所有环境变量指向这些固定路径避免路径里有空格和中文注意路径里千万不要有中文和空格这是无数人用血泪换来的教训。Program Files这种带空格的路径会让某些脚本解析出错。3. 核心组件安装与配置实操3.1 JDK 8 安装与环境变量JDK 8 的安装没什么好说的下载安装包一路下一步就行。关键是环境变量的配置。你需要设置三个东西JAVA_HOME指向 JDK 安装根目录比如D:\dev\jdkPATH追加%JAVA_HOME%\binCLASSPATH一般设.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar不过现代 Java 项目其实不太依赖这个验证方式是打开新的命令行窗口执行java -version看到1.8.0_xxx就对了。这里有个细节如果你机器上装了多个 JDKPATH里谁在前面谁生效。建议把 JDK 8 的路径放在最前面或者干脆把其他 JDK 的路径从PATH里删掉。3.2 Maven 3.6.3 安装与仓库配置Maven 解压到D:\dev\maven后同样配置MAVEN_HOME和PATH。真正重要的是conf/settings.xml的配置这里要做两件事配置本地仓库路径和配置镜像仓库。本地仓库默认在C:\Users\你的用户名\.m2\repository这个路径会随着依赖增多变得非常大建议改到其他盘localRepositoryD:\dev\maven-repo/localRepository镜像仓库配置是为了加速下载。国内访问中央仓库速度不稳定配置一个国内镜像能快很多mirror idaliyun-mirror/id mirrorOfcentral/mirrorOf nameAliyun Maven Mirror/name urlhttps://maven.aliyun.com/repository/central/url /mirror提示镜像的mirrorOf写central表示只代理中央仓库。如果你项目里还配了其他仓库需要相应调整否则可能拉不到某些特殊依赖。配置完后执行mvn -v能看到 Maven 版本和 Java 版本信息就说明配置生效了。3.3 Scala 2.11.8 安装与 IDEA 插件Scala 的安装包直接解压到D:\dev\scala配置SCALA_HOME和PATH。命令行执行scala -version验证。IDEA 这边需要装 Scala 插件。2020.1 社区版默认不带 Scala 支持你要去插件市场搜 Scala 安装。这里有个坑插件版本要和 IDEA 版本匹配。2020.1 对应的 Scala 插件版本大概是 2020.1.x 系列装最新版可能会提示不兼容。如果在线安装失败可以去插件官网下载对应版本的离线包用Install Plugin from Disk方式安装。装完插件重启 IDEA新建项目时应该能看到 Scala 选项了。3.4 Hadoop winutils 的配置这是 Windows 上跑 Spark 最容易被忽略的一步。Spark 底层会调用 Hadoop 的文件系统 API在 Windows 上需要winutils.exe和hadoop.dll这两个文件。你需要下载对应 Hadoop 版本的 winutils 包解压到某个目录比如D:\dev\hadoop然后设置HADOOP_HOME环境变量指向它并把%HADOOP_HOME%\bin加到PATH里。同时还要把hadoop.dll复制到C:\Windows\System32目录下否则会报UnsatisfiedLinkError。这个操作需要管理员权限。注意winutils 的版本要和 Spark 依赖的 Hadoop 版本对应。Spark 2.4.x 默认依赖 Hadoop 2.7.x所以你要找 2.7.x 版本的 winutils。版本不对可能会出现莫名其妙的错误。4. Maven 项目配置与依赖管理4.1 创建 Maven 项目并添加 Scala 支持在 IDEA 里新建项目选择 Maven不要选 Scala 模板。为什么因为 Scala 模板生成的项目结构有时候和 Maven 标准结构不一致后期加依赖容易出问题。用纯 Maven 项目然后手动加 Scala 插件和依赖结构最干净。创建时填入 GroupId 和 ArtifactId比如com.example和spark-demo。创建完成后在src/main下新建scala目录然后右键Mark Directory as-Sources Root。这样 IDEA 才会把 Scala 文件当源码处理。4.2 pom.xml 核心依赖配置pom.xml是整个项目的核心依赖配错了后面全是坑。下面是我用了很多次的配置模板properties maven.compiler.source1.8/maven.compiler.source maven.compiler.target1.8/maven.compiler.target scala.version2.11.8/scala.version spark.version2.4.5/spark.version hadoop.version2.7.7/hadoop.version /properties dependencies dependency groupIdorg.scala-lang/groupId artifactIdscala-library/artifactId version${scala.version}/version /dependency dependency groupIdorg.apache.spark/groupId artifactIdspark-core_2.11/artifactId version${spark.version}/version /dependency dependency groupIdorg.apache.spark/groupId artifactIdspark-sql_2.11/artifactId version${spark.version}/version /dependency dependency groupIdorg.apache.hadoop/groupId artifactIdhadoop-client/artifactId version${hadoop.version}/version /dependency /dependencies这里解释几个关键点。spark-core_2.11后面的_2.11表示这个 jar 是用 Scala 2.11 编译的必须和你的 Scala 版本一致。spark-sql如果你不做 SQL 相关开发可以不引但一般建议加上因为很多场景会用到 DataFrame。hadoop-client是为了解决 Windows 上的文件系统调用问题虽然 Spark 会间接引入 Hadoop 依赖但显式声明版本能避免版本冲突。4.3 Scala 编译插件的配置Maven 默认不认识 Scala 代码需要加scala-maven-pluginbuild plugins plugin groupIdnet.alchim31.maven/groupId artifactIdscala-maven-plugin/artifactId version4.4.0/version executions execution goals goalcompile/goal goaltestCompile/goal /goals /execution /executions configuration scalaVersion${scala.version}/scalaVersion /configuration /plugin /plugins /build这个插件的版本也有讲究。4.4.0 对 Scala 2.11 支持比较好太新的版本可能要求 Scala 2.12。配置完后IDEA 右侧 Maven 面板点刷新依赖就会开始下载。第一次下载会比较慢因为 Spark 的依赖树很庞大几百兆是正常的。提示如果下载卡住不动检查镜像配置是否生效。可以在 IDEA 的 Maven 设置里勾选Work offline先试试如果本地仓库已经有依赖就能跳过网络请求。5. 第一个 Spark 程序的编写与运行5.1 WordCount 代码实现环境搭好后写个 WordCount 验证是最直接的。在src/main/scala下新建WordCount.scalaimport org.apache.spark.{SparkConf, SparkContext} object WordCount { def main(args: Array[String]): Unit { val conf new SparkConf() .setAppName(WordCount) .setMaster(local[*]) val sc new SparkContext(conf) sc.setLogLevel(WARN) val input sc.textFile(data/input.txt) val counts input .flatMap(_.split(\\s)) .map(word (word, 1)) .reduceByKey(_ _) counts.collect().foreach(println) sc.stop() } }setMaster(local[*])表示用本地所有 CPU 核心跑[*]会自动检测核心数。setLogLevel(WARN)是为了减少控制台日志输出不然 Spark 的 INFO 日志能刷屏。5.2 运行配置与参数说明在 IDEA 里直接右键运行WordCount就行。但有几个地方要注意。第一data/input.txt这个路径是相对于项目根目录的你需要在项目根目录下建一个data文件夹里面放一个input.txt随便写几行英文。第二如果报winutils相关的错说明前面的 Hadoop 配置没生效检查HADOOP_HOME和PATH。运行成功后控制台会输出每个单词和它的出现次数。看到这个结果说明整套环境已经跑通了。5.3 打包与提交模式的差异本地运行用的是local[*]但实际项目最终是要打成 jar 包提交到集群的。打包时要把setMaster去掉因为集群模式由提交命令指定 master。打包命令是mvn clean package生成的 jar 在target目录下。这里有个常见问题如果pom.xml里没有配置maven-shade-plugin或maven-assembly-plugin打出来的 jar 不包含依赖提交到集群会报ClassNotFoundException。本地运行不需要这个因为 IDEA 会把依赖加到 classpath 里。所以如果你要提交集群需要额外配置打包插件。6. 常见问题排查与避坑经验6.1 典型报错速查表报错信息原因解决方案Could not locate executable null\bin\winutils.exe缺少 Hadoop winutils配置 HADOOP_HOME 并放好 winutils.exeNoSuchMethodError或NoClassDefFoundErrorScala 版本不匹配检查 spark-core 后缀和 scala.version 是否一致UnsatisfiedLinkError: org.apache.hadoop.io.nativeio.NativeIO缺少 hadoop.dll复制 hadoop.dll 到 System32java.lang.OutOfMemoryError本地内存不足调大spark.driver.memory或减少数据量IDEA 编译卡死或代码飘红Scala 插件版本不兼容换用与 IDEA 版本匹配的插件6.2 依赖冲突的排查方法Spark 的依赖树很深很容易出现同一个库多个版本共存的情况。排查方法是执行mvn dependency:tree看有没有版本冲突。如果发现某个库有多个版本可以用exclusions排除掉不需要的那个。我遇到最多的是jackson和netty的冲突。Spark 自带的版本和你项目里其他依赖引入的版本不一致时运行时会报NoSuchMethodError。解决办法是在pom.xml里显式声明统一版本或者用dependencyManagement锁定版本。6.3 内存参数调优经验本地模式下Spark 默认的 driver 内存可能不够用尤其是处理稍大数据集时。可以在SparkConf里加.set(spark.driver.memory, 2g) .set(spark.executor.memory, 2g)本地模式下 executor 和 driver 在同一个 JVM 里所以主要调 driver 内存。但也不能调太大超过物理内存反而会频繁 GC。一般 4G 到 8G 之间比较合适具体看你机器配置。注意spark.driver.memory在代码里设置有时不生效因为 JVM 已经启动了。更可靠的方式是在 IDEA 的运行配置里加 VM options-Xmx2g。6.4 日志噪音的处理技巧Spark 默认输出大量 INFO 日志调试时很干扰。除了setLogLevel(WARN)还可以在src/main/resources下放一个log4j.propertieslog4j.rootCategoryWARN, console log4j.appender.consoleorg.apache.log4j.ConsoleAppender log4j.appender.console.targetSystem.err log4j.appender.console.layoutorg.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern%d{yy/MM/dd HH:mm:ss} %p %c{1}: %m%n这样日志会清爽很多只保留警告和错误。7. 环境验证与后续扩展方向7.1 完整验证清单环境搭完后建议按这个清单逐项验证java -version输出 1.8.xmvn -v输出 Maven 3.6.3 和 Java 1.8scala -version输出 2.11.8IDEA 里能正常创建 Scala 文件且代码提示正常WordCount 能跑出结果控制台没有 winutils 相关报错全部通过说明环境没问题了。7.2 从本地模式到集群模式的过渡本地跑通后下一步通常是连远程集群或提交到集群。连远程集群需要把setMaster改成spark://host:7077并确保网络能通。提交集群则要打包并写提交脚本。这个过渡过程中最容易出问题的是依赖打包和序列化。Scala 的闭包序列化在分布式环境下要求所有引用的类都可序列化本地模式不会暴露这个问题集群模式会。7.3 我个人的几条实操建议第一环境变量改完后一定要开新的命令行窗口验证旧窗口不会自动加载新变量。第二IDEA 的 Maven 设置里把Maven home directory指向你自己装的 Maven不要用 IDEA 自带的自带版本可能和你的配置不一致。第三项目路径和 Maven 仓库路径都不要放在 C 盘重装系统时你会感谢自己。第四遇到奇怪的编译错误先mvn clean再重新编译很多时候是缓存问题。这套环境我用了挺长时间整体稳定性不错。唯一需要注意的是 IDEA 2020.1 对某些新版 Scala 插件的兼容性如果插件市场提示不兼容去官网找历史版本手动装就行。环境搭好只是第一步后面 Spark 的算子、调优、SQL 才是真正花时间的地方但至少你不用再被环境问题卡住了。
阅读完成 · 觉得有帮助?
咨询建站