0%

实习踩坑记录:Spark+Scala大数据开发问题汇总

0.环境

  • spark 2.3
  • scala 2.11.8
  • hadoop 2.6.0-cdh5.15.1

1. 任务要求

  • scala调用python程序
  • 分布式运行
  • 服务器上不具备环境(将python程序封装成restful服务,然后scala调用接口,直接用cmd调用python程序耦合度存在问题)

2.问题

  • 找不到或无法加载主类

    maven依赖包冲突

  • maven仓库中的LastUpdated文件生成原因及删除

    在maven在下载jar的时候中断了就会产生lastUpdate文件,批量删除Maven仓库未下载成功.lastupdate 的文件

  • 没有相关方法(noSuchMethodError)
    1. maven没有下载相关的源码包(在仓库里面看有没有XXX.source.jar)
    2. 在集群上面跑程序是否每一台机器都需要导入相关的使用的包
    3. httpclient4以上的版本不支持在spark多节点上使用
    4. 本地和集群的spark或scala版本不一致
    5. 查看源码
  • maven打包参数

    clean清除以往残留
    package打包
    assembly自定义打包参数

  • spark单机跑程序命令

    spark-submit –class ScalaMain ./test/ScalaJarT.jar local

  • spark为什么在后面会重新调用前面的dataframe操作代码

    Spark 2.1.0及以前的版本有一个很坑爹的问题,如果persist一个df1后unpersist 与df1相关的df0,那么df1也会被unpersist掉,导致后续用到df1的地方又需要重新算df1,降低性能。所以在后面需要用到df1的时候会重新调用df0

3.其他

困扰了快一周左右的问题终于解决了,写好的程序在本地可以运行但是放在服务器上总是报noSuchMethodError的error

1
java.lang.NoSuchMethodError: org.apache.http.impl.client.DefaultHttpClient.execute at 

或者NoSuchFieldError的error

1
2
java.lang.NoSuchFieldError: INSTANCE
at org.apache.http.impl.io.DefaultHttpRequestWriterFactory.<init>(DefaultHttpRequestWriterFactory.java:52)

查了很多资料甚至把jar包反编译回去看源码都没有解决,网上都说是htpclient的包和某个maven包相冲突等等问题。根据网上的能查到的国内外的各种资料总结了以下几种猜想并尝试一一解决问题,大致如下:

  1. 刚开始在查看报问题包的时候,想查看源码却发现公司内网的maven仓库没有自动把源码包下载下来,是否是因为没有下载源码包的问题所以打包后的程序无法找到相关方法?
1
解决方法:把相同版本的httpclient的源码包导入到工作机器上打包运行仍然出现这种问题。猜想失败
  1. 在集群上面跑程序是否每一台机器都需要导入该程序使用的包?
1
解决方法:据自己过去的学习的知识来说,印象中好像是不需要的。但是之前对集群东西摸得比较少,仔细想了下,把程序放在spark上面分布式运行请求单独的接口,但是spark在分布给每一个worker任务的时候都是随机分配的,如果worker上面没有相关的依赖包那怎么请求呢。又让我产生了怀疑,然后通过查阅资料发现通过maven打包运行的程序是不需要每一台机器都要有依赖包的。
  1. httpclient4以上的版本是否支持在spark多节点上使用?
1
解决方法:查阅资料发现httpclient4是支持在集群使用的
  1. 使用的httpclent版本是否和spark版本相冲突?
1
解决方法:之前一直觉得版本是不会出现问题的,忽略了最小的问题也是最严重的问题。查看了服务器集群的版本之后,服务器上面有spark1.6和spark2.3两个版本,我在运行程序的时候使用的sparksubmit命令是1.6版本的命令。但是我本地电脑上面装的是spark2,所以之前的程序一直可以本地跑然后放服务器上就死掉了。然后把程序放服务器上面的spark2跑一下发现竟然还是死掉了,很奇怪。把原来的scala程序仔细翻翻发现竟然是spark1版本的,真是xuema坑爹。然后鼓捣鼓捣觉得绝对是是spark的和httpclient的版本冲突问题,把原来的httpclient4.5.5改成了3.1版本的,这里又有问题了,httpclient4和httpclient3两个版本的差别还是挺大的(主要是里面很多的类和参数都进行了修改在4的版本中被弃用了,所以在运行的时候会报没有方法或者没有field的问题)。意思就是调用接口的代码要重写,其实并没有很多内容,但是问题难在httpclient4的网上可供参考的代码还挺多的但是httpclient3就太古老了,大家在用这个包的时候估计scala还没有被发明出来,所以找scala写的httpclient3基本没有。然后硬着头皮对着java版本的调用方式写了一套scala的,本地用的是spark2,可以运行(很多框架都是向下兼容的不假)。然后放集群上面跑一下,两个版本的spark都可以运行没问题。
  • 总结:

    鉴于框架向下兼容的特性用什么还是要用低版本的,当没有特殊需求的时候。
    头铁的时候是可以把墙撞烂的,不要害怕墙的坚硬。。。。要勇于尝试