淘先锋技术网

首页 1 2 3 4 5 6 7

说在前面

最近因为项目需要,处理的数据集变大了,用单机处理起来比较费劲,虽然也能得到结果,但是总觉得应该尝试一下新技术。说新技术,其实也不新了。第一次在公众号上写文章,先极简地自我介绍一下。我叫哈明,这是我用了好几年的微信昵称,就不取别的名字了,简单点。

写这篇文章的目的是为了记录一下自己最近在搭建Spark集群中的点点滴滴,那些莫名其妙的坑。我在想设计者是不是在故意抬高使用门槛,还是说这玩意就得这么设计,没别的法。我去年研究了一段时间Flink,我用Flink主要是来做设备状态监测用的,也发了几篇没啥用的论文,申请了2项专利,1项已经授权了,就觉得它有意思,好玩,当然也很强大。也是在去年,组里曾经的java小伙伴搭建了一个小型的集群,铁打的集群流水的兵。一年多了,我基本上就是用这个集群做做数据源,很多代码都是在自己的工作机上测试。我不敢动那个集群,怕把它搞崩了。就在最近,我决定动它了,因为它没有部署Spark-Yarn,于是就有了下面的故事。

因为自己没弄过集群搭建的事儿,对linux操作也不熟练,于是我决定尽量减少对原集群的影响,但是事与愿违,我也不知道这后面是什么千丝万缕的关系,反正搞着搞着集群就开始不听话了,像脱缰的野马。

开始改建Hadoop集群

好了,言归正传。搭建集群,最好是从干净的操作系统开始,按照流程一步步来。我在原来的集群上增加修改,虽然省去了很多工作,但也不让人省心。可能是因为版本冲突,解决了一个问题又蹦出一个问题,我差点另起炉灶了。我要改建的集群很小,只有3个节点,别看只有3个节点,但是该有的都有了,毕竟“三生万物”嘛。原来集群的zookeeper版本是3.6.2,hadoop版本是2.8.3,集群上也安装了高版本的hadoop3.2.2,但是默认启动低版本的。由于我在b站尚硅谷上学的Spark教程用的是hadoop3编译过的Spark,所以我需要把我的集群改成hadoop3.2.2。接下来就是我在被各种问题搞得懵圈又懵圈中度过的一周,好在结果是成功的,但我在写这篇文章时我依然有很多不明白的地方,我也正是想借助写作来梳理问题和解决问题的思路,趁着记忆还新鲜给自己做个记录,为以后遇到类似问题能有个参照,如果恰好也能帮到一些朋友那也最好不过了。对于从零开始搭zookeeper/hadoop集群的朋友,可以参考https://blog.csdn.net/JunLeon/article/details/120689889。如果连虚拟机和操作系统都没有,那么请去B站尚硅谷(我不是打广告的)看最帅的男人讲的hadoop教程。

首先,zookeeper我没动,就用原来的。这块我就不展开聊了。

然后,说说最让我头疼的hadoop吧。我的集群三个节点都安装了新旧两个版本的两个hadoop,在HADOOP_HOME/etc/hadoop路径下的几个关键配置文件core-site.xml/hdfs-site.xml/yarn-site.xml还有worker都是按照zookeeper高可用(HA)的方式来配置的。这里面坑中之坑就是core-site.xml中下面这个配置:

<property>
  <name>hadoop.tmp.dir</name>
  <value>/opt/datas/hadoop/data/temp</value>
</property>

hadoop.temp.dir是 hadoop文件系统依赖的基本配置,很多配置路径都依赖它,它的默认位置是在 /tmp/{$user}下面,注意这是个临时目录!!!(这句话是我引用的,为了尊重原作,我标紫色所以要自己配置好自己的路径,这块的坑先讲到这,后面会继续提到。

hadoop启动前要在每个节点通过"zkServer.sh start"命令启动zookeeper,如果我的集群不改,我直接用"start-all.sh"命令在节点1就能启动hadoop集群,此时启动的是hadoop2.8.3版本的集群。为了能启动,我需要"vim /etc/profile"去修改我的环境变量,就是把原来的2.8.3注释掉,看下图:

 为了保险起见,我把三个节点都改过来。然后,我不管三七二十一就用"start-all.sh"命令把集群启起来了,在启动之前我已经按照尚硅谷教程中spark-yarn的搭建和配置方式,把spark-yarn弄好了。我迫不及待地给集群提交下面这个任务:

bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master yarn \
--deploy-mode cluster \
./examples/jars/spark-examples_2.12-3.0.1.jar \
10

第一个坑出现了

本来以为是见证奇迹的时刻来了,可是野马不听话,直接踹了我一脚,告诉我什么叫做心急吃不了热豆腐。我想想第一个问题是啥,(好不容易调好了,我不想把集群搞坏来复现问题,可能想复现也没那么容易),我去当时我百度的错误记录上查查去我遇到的第一个问题是什么,经过一番搜索,找到了当时懵逼的我向度娘问了啥问题:

java.net.ConnectException: Call From db101/10.2.31.144 to db102:9000 failed

就是这个问题从2022年6月15日困扰到2022年6月22日,一周时间。在网上找了很多解决办法,无外乎两种说法:1)配置问题;2)网络问题。大部分解释都是配置没问题,网络问题是导致连接不上的原因,而我的集群之前一直正常使用,而且网络连接、防火墙设置、端口状态之类的都没有问题。而我的配置也是按照教程来的。我先后尝试了重启大法、格式化hadoop hdfs,均以失败告终。后来,我想是不是两个版本的hadoop发生冲突了,我愣是把2.8.3版本的hadoop从集群中删除了,格式化和重启都试过了,还是报那个错误。当然,后面我都不提交spark任务测试了,用"hadoop fs -ls"命令就得出这样的问题。问题到底出现在哪,怎么成了疑难杂症了,网上的说法太杂,找不到适用于我的问题的解决对策,直到我看到了尚硅谷最帅的男人(我真不是做广告)讲hadoop里的一段,我深受启发,先上图:

 

最帅的男人运笔还是很潇洒的,这红圈圈就是他画的。原来我此前的格式化都是瞎格!!!我先是去到我的节点机器路径下找到VERSION文件,一看果然cluserID不一样,这集群不出问题才怪呢。于是我把data和logs目录全都删了,重新格式化,重新启动集群,再运行"hadoop fs -ls"命令就不报错了,然后我在想是不是我不删除2.8.3版本的hadoop也行。这个最棘手的问题的解决现在看来也没什么,可当时对我来说真的是一筹莫展。

记得第一次启动zookeeper下的hadoop集群(我三个节点名称分别是db101,db102,db103),要按照下面的步骤进行:1)在三个节点上启动journalnode;2)在三个节点上启动故障检测zkfc;3)在db101上格式化hdfs(格式化前一定要删除全部机器上的data和logs);4)在db101和db102上启动namenode;5)在三个节点上启动datanode;6)在db101和db102上启动resourcemanger;7)在三个节点上启动nodemanager。以后的启动就简单多了,start-all.sh就行。这也是小伙伴留下的文档里说到的,不过他文档里也有些小瑕疵,完全照搬操作会有坑,接下来我就讲这个坑,这个坑也困扰了我差不多1天。

第二个坑

在小伙伴的文档里说,在db101和db102上启动namenode之后,要在db102上执行"hdfs namenode -bootstrapStandby",我印象中我第一次调成功集群时这个命令没起作用,我一开始没管它,也能正常执行后续的sparkpi作业。在我调成功集群的第二天,正当我兴高采烈地继续Spark研究时,我在节点2启动了1个spark-local下的spark-shell,想来进行学习和测试,结果非但我spark-shell下的程序没执行成功,还导致我后来把hadoop集群再启动提交sparkpi任务后,一直无法成功执行任务,执行client模式报的错误是:

Call From db101/10.2.31.144 to db102:9000 failed on connection exception

执行cluster模式报的错误是:

Application application_1655974506088_0002 failed 2 times due to AM Container for appattempt_1655974506088_0002_000002 exited with exitCode: 13

真是阴魂未散啊,这个问题怎么又来了,不过这次只显示db101call不到db102,原来是db101连自己都call不到。于是我又走了一遍格式化、重启的路子,问题还是没得到解决。后来,我又把spark-local给删了,还是于事无补。原来问题的根源在于,首次启动hadoop时,不要执行"hdfs namenode -bootstrapStandby"操作,这个操作会把节点2的namenode进程结束掉,直接导致任务提交时db101不能访问db102,db102namenode都没启动可不就call不到嘛。

第三个坑

最后说一下在zookeeper HA下的hadoop集群下配置spark历史服务的问题。一开始我按照尚硅谷Spark教程来配置我的spark-yarn历史服务,要修改两个配置文件,分别是spark-env.sh文件和spark-defaults.conf文件。我一开始spark-env.sh文件的配置如下:


export SPARK_HISTORY_OPTS="
-Dspark.history.ui.port=18080
-Dspark.history.fs.logDirectory=hdfs://db101:9000/sparklog
-Dspark.history.retainedApplications=30"

 spark-defaults.conf的配置如下:

spark.eventLog.enabled           true
spark.eventLog.dir               hdfs://db101:9000/sparklog


spark.yarn.historyServer.address=db101:18080
spark.history.ui.port=18080

结果,每次我在db101节点启动spark历史服务时,都查看不到进程,在浏览器中输入db101:18080页面也打不开。后来我通过百度查和自己思考,原来在zookeeper高可用hadoop集群中配置spark历史服务,要将日志路径设置为mycluster,需要将"hdfs://db101:9000/sparklog"改成"hdfs://mycluster/sparklog",然后在db101和db102两个节点上创建sparklog路径。这里注意,千万不要改成"hdfs://mycluster:9000/sparklog",不然执行sparkpi作业又会不成功,而且会报这样的错误:

Caused by: java.io.IOException: Port 9000 specified in URI hdfs://mycluster:9000/sparklog but host 'mycluster' is a logical (HA) namenode and does not use port information.

总结

到目前为止,我搭建Spark on Yarn遇到的几个大坑已经被我填平了,多次重启并提交任务都能成功执行作业。

通过这次填坑,我意识到搭建集群和配置操作一定要仔细,遇到问题一定要认真读错误信息,网上往往没有现成的答案,需要根据各种线索综合分析得到属于自己特定问题的特定答案。大数据技术好比葵花宝典,一开始告诉你欲练此功,必先自宫,等你真自宫了,再看它又说即使自宫未必成功。我把集群里的其他版本的hadoop和spark都删了,相当于自宫了一半,结果还是失败,这说明什么,说明问题的根源没有找到胡乱操作是行不通的,好在我还保留了关键的东西,经过慢慢修炼,把碰到的问题逐个解决,现在这匹野马开始有点被驯服的意思。也许在高手看来,我这都属于菜鸡操作。作为非计算机、非大数据科班出身的我,有一颗对技术喜爱的心,把这些利器用在自己的专业领域里,发挥一些作用,碰撞一些火花出来,也是一件令人高兴的事儿。好了,CSDN上第一篇文章到此结尾。这篇文章和我的个人公众号上的文章同步,也欢迎大家关注我的微信公众号“哈明ST”。