IDEA开发Spark应用并提交本地Spark 2.1.0 standalone集群运行

本文主要参考了如下两篇博文:

Windows下IntelliJ IDEA中调试Spark Standalone

怎么解决java.lang.NoClassDefFoundError错误

一、通过IDEA连接远程集群运行应用就是个大坑。。

写在2017年10月3日凌晨0点57分:

最初这篇博文的名字是“IDEA开发Spark应用并提交远程Spark 2.1.0 standalone集群运行”,当时以不能SSH免密码登录远程主机为由,直接连接本地集群运行应用,后来又尝试了一下通过IDEA连接部署在实验室服务器上的Spark集群来运行应用,然后就发现这里实在是坑太多。如果部署模式是“client”,则会在本地主机起一个driver进程,而从本地主机序列化分发jar包到集群各从节点要求本地主机能够SSH免密码登录各从节点!!(当然运行时只需要网络互通即可)如果部署模式是“cluster”,然后IDEA运行项里配置“VM options”为-Dspark.submit.deployMode=cluster,结果很不幸,driver依然在本机运行,然后执行器和驱动器无法互相通信。

通过spark-submit脚本,设置部署模式为cluster,这样driver会在某一个worker上启动,然而我们的jar包依然在本机,还是需要序列化分发到各节点,然而这样就需要本地主机可以免密码SSH登录所有集群节点!!

当然本地开发测试还是可以通过IDEA连接本地集群运行应用,毕竟借助IDEA,我们只需点一下“运行”即可,还是方便很多。所以啊,本文决定把题目和内容改一下,把远程改成本地!

二、前言

虽然之前也有许多博文讲如何基于IDEA来开发运行Spark应用,但是他们大多数都以本地模式运行(例如:conf.setMaster("local[*]")),而本地模式只是在本机以多线程方式运行Spark应用,这与standalone模式运行有很大差别。

此外,虽然也有一些博文介绍了如何使用IDEA将开发的Spark应用提交到本地Spark集群执行,但是这些博文涉及的Spark版本都比较老,较新版本的Spark(例如2.1.0及以后)取消了lib目录,也就是说新版本没有assembly jar包(例如:spark-assembly-1.5.2-hadoop2.6.0.jar),取而代之的是jars目录,这就使得在新版本里,依赖包的添加发生了一些变化。

综上所述,还是很有必要重新写一篇关于IDEA提交Spark应用到本地集群的博文,这篇博文关注点在于如何让IDEA连接Spark 2.1.0 standalone集群

这篇博文首先介绍了几种Spark应用开发和运行的方式,然后介绍了如何通过IDEA连接Spark standalone集群来开发运行Spark应用,最后对可能发生的错误给出了解决方法。

注意:由于大部分情况下,我们不能随意访问远程主机,例如不能直接ssh免密码登录远程主机,所以本文只是将IDEA连接到了本机的Spark 2.1.0 standalone集群,也就是将Spark应用提交到本地集群运行。

三、开发环境

操作系统:CentOS 7

Spark:2.1.0

IDEA:社区版2016.3.1

Scala:2.11.8

JDK:1.8.0_111

四、Spark应用开发运行综述

1、开发

用Scala开发Spark应用,官方推荐使用SBT项目构建工具,当然由于Scala基于JVM,所以使用Maven也是可以的。有时我们想在项目中混合使用Java和Scala,这时Maven就成了最佳选择,当然这个时候就需要在pom.xml中配置Java和Scala的编译工具。

可以纯粹使用项目构建工具SBT或者Maven来完成Spark开发(不借助IDE),包括按照模板创建项目、编译、构建项目、打包和发布等等。当然也可以借助IDEA集成的SBT和Maven插件来高效完成上述工作(IDE+项目构建工具)。

当然这篇博文只使用IDEA来完成上述工作,没有使用项目构建工具。

2、运行

开发完项目后当然就要运行我们的Spark应用了,运行也有好几种方式。

(1)第一种方式主要用于开发测试完毕,准备线上运行。借助IDEA或者使用项目构建工具将Spark应用打成Jar包,接着上传到服务器(windows使用FileZilla,Linux使用scp命令),然后通过spark-submit脚本连接集群(通过master的URL可以连接到不同集群)并运行Spark应用。

(2)第二种方式是本地测试。打包后直接提交本地Spark standalone集群(伪分布式,本机运行master和worker)。

(3)开发时会频繁地运行Spark应用,前面两种方式就显得比较麻烦(需要打包、上传、提交),第三种方式用于开发过程中。通过IDEA连接Spark standalone集群,只需点击IDEA的“运行”按钮即可运行Spark应用(不需要手动打包,不需要上传到服务器,不需要手动运行spark-submit脚本)。当然也可以以local模式运行(可以在应用程序中使用conf.setMaster("local[*]")或者在IDEA运行项中配置“VM options”为-Dspark.master=local[*],然后点击IDEA的“运行”按钮),此时在本地以多线程方式运行Spark应用,local模式不需要开启Spark集群。

下面介绍如何通过IDEA连接Spark standalone集群,来快速开发调试Spark应用。

五、通过IDEA将开发的Spark应用提交到本地Spark 2.1.0 standalone集群运行

1、前提要求(版本信息见“开发环境”)

(1)需要有一个Spark standalone集群,不需要hdfs,能启动运行即可。

(2)IntelliJ IDEA、Scala插件、Java JDK、Scala SDK都已安装配置完毕。

2、创建项目

新建一个Scala项目。启动IntelliJ IDEA,选择New Project,然后选择Scala,点击下一步,接着配置项目名称、SDK版本和项目位置等。注意:IDEA中项目的概念类似于Eclipse中的工作区(workspace),而IDEA中模块(module)的概念类似于Eclipse中的项目。

图1 新建一个Scala项目
图2 配置项目(名称、SDK和位置等)

3、添加依赖的Jar包

如前文所述,较新版本的Spark(例如2.1.0及以后)取消了lib目录,取而代之的是jars目录,所以这里依赖包的添加相比于旧版本发生了一些变化。

首先按如下步骤(图3、图4和图5)为我们开发的Spark应用添加依赖,把Spark 2.1.0中的jars目录整个添加进来(这样jars目录里所有的jar包都会被添加到classpath中),并调整它的scope为“编译”(这样我们后面打的包会包括jars目录里所有的jar包)。

看到这里,读者可能会心生疑惑,我们开发的应用事实上用不着这么多的jar包,例如关于机器学习或者流计算的jar包我们肯定用不上,另外,这些jar包Spark集群中都有,为什么还要把scope设为“编译”呢?

如果是手动打包然后通过spark-submit脚本运行应用的话,确实只需添加几个jar包即可,而且scope还应该设为“provided”,这样可以减少最终生成jar包的大小。然而通过IDEA提交Spark应用到本地集群,还就必须按前述步骤做,否则会报java.lang.NoClassDefFoundError的错误(不把整个jars目录添加到classpath中会报错,不把它的scope设为“编译”也会报错)。

java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError这两种错误看起来有点像,但它们是完全不同的。NoClassDefFoundError是指JVM运行时无法在classpath中找到对应的类进行加载;而ClassNotFoundException是指编译的时候classpath中找不到对应的类。

图3 为Spark应用添加依赖
图4 把Spark 2.1.0中的jars目录整个添加进来
图5 调整scope为“编译”

4、完成代码

在src目录下新建一个名为WordCount的object,这是我们的main class。接着在源文件中输入Spark的HelloWorld程序——WordCount。因为这里连接的是本地Spark 2.1.0 standalone集群,所以直接从本地读取文件。

有两点需要注意:

(1)因为要提交Spark应用到本地集群运行,所以需要配置master的URL,可以在应用程序中使用conf.setMaster("spark://host:port")或者在IDEA运行项中配置“VM options”为-Dspark.master=spark://host:port,“host”就是master所在的主机名,如果没有在/etc/hosts中建立主机名和IP的映射关系,则直接使用IP。

(2)通过conf.setJars(List("/path/to/xxx.jar")),告诉Spark集群我们要提交的包含作业代码的jar包在哪里,记住路径中千万别包含中文,不然会出错。

图6 在src目录下新建WordCount.scala
图7 输入WordCount代码

5、配置打包

即便是通过IDEA提交Spark应用到本地集群执行,我们还是需要配置打包。Spark应用之所以能够分布式运行,正是因为jar包被分发到了各个worker之中。

我们将应用程序打成可执行jar包,并为它设置main class,然后再把“构建项目自动打包”的选项勾上,这样才能做到点击“运行”就提交到本地集群运行。

图8 将Spark应用打包
图9 可执行jar包,配置main class
图10 构建项目时自动打包

6、配置IDEA运行项

这里结合spark-submit脚本,说明一下IDEA是怎么做到一键提交Spark应用到本地集群执行。当我们点击“运行”按钮,IDEA会自动构建项目,并重新打包;然后根据应用程序中的conf.setJars(List("/path/to/xxx.jar")),可以找到需要提交到集群的jar包;根据conf.setMaster("spark://host:port")或者IDEA运行项中“VM options”的-Dspark.master=spark://host:port连接到Spark standalone集群,这相当于配置spark-submit脚本的--master;然后IDEA运行项中的“Main class”指定了Spark应用的main class,这相当于配置spark-submit脚本的--class;如果还想为Spark应用做一些其他配置,可以通过conf.set("xxx", "XXX")或者“VM options”添加一些其他配置(形如-Dxxx.yyy=zzz);传给Spark应用main方法的参数在“Program arguments”中输入。

所以使用IDEA连接集群,通过IDEA将Spark应用提交本地集群执行,其实就是IDEA替我们完成了打包和执行spark-submit脚本的工作。

图11 配置IDEA运行项

7、启动Spark集群

在点击“运行”按钮之前,需要确保目标本地Spark standalone集群已经启动。

注意:我们开发时使用的Spark版本要和本地集群一致。

8、运行,观察IDEA控制台结果,观察Spark Web UI。

终于到了最后一步,点击“运行”按钮,见证奇迹吧(2333333......)。

可以看到,控制台成功输出了词频统计。也可以打开Spark Web UI,详细看一下应用执行情况。

图12 控制台输出结果
图13 Spark Web UI查看应用详细执行情况

六、可能出现的错误

1、可能会出现如下错误:创建SparkContext时出现异常

java.net.BindException: Cannot assign requested address: Service 'sparkDriver' failed after 16 retries (starting from 0)! Consider explicitly setting the appropriate port for the service 'sparkDriver '(for example spark.ui.port for SparkUI) to an available port or increasing spark.port.maxRetries.

解决方法:在IDEA运行项“VM options”中加入“-Dspark.driver.host=127.0.0.1”和“-Dspark.driver.port=7077” 这两项, 配置driver进程在本机的7077端口运行。

2、还可能出现这个错误:Hadoop权限错误

org.apache.hadoop.security.AccessControlException: Permission denied: user=yourUsername, access=WRITE, inode="/user/otherUsername/":otherUsername:supergroup:drwxr-xr-x

这是因为,HDFS中每个用户都有自己的home目录(与Linux系统一致),用户自己的目录只有该用户拥有写权限,远程连接Spark集群运行应用时,若使用本机用户尝试对其他用户在HDFS中的home目录进行写操作,会出现这个问题。

解决办法:

(1)修改Hadoop 配置文件hdfs-site.xml,设置dfs.permissions.enabled为false即可,这样不会再有权限限制,具体如图14所示。当然,开发测试完了最好还是把这个权限限制机制打开。

图14 修改Hadoop配置文件hdfs-site.xml

(2)使用和远程集群一致的用户,或者在同名用户home目录下进行写操作。


转载请注明如下内容:

文章来自简书,作者:就是杨宗

原文链接:http://www.jianshu.com/p/b4e4658c459c

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容