Spark 坑坑记

背景

​ 公司里想做一个分析的业务,数据全都在MySQL里,就想着把数据导入到Kudu中后再做进一步的分析。由于在导数据过中可能会需要etl,而且数据的实时性要求并没有很高,对比了一下spark跟storm觉得spark的微批处理的思想很适合这种情况,于是就愉快的决定了。

上手

​ 我个人比较学院派,就是学习一个东西喜欢找书看。书里的体系是比较好的,从产生背景、基础知识到进阶知识都会有涉及到,我看的是《Spark in Action》,这本书主要介绍了spark的处理数据流程,spark的rdd(弹性数据集)的各种相关操作,不难,其实就是那些函数式相关的操作,没有接触过函数式语言的只要了解过Java8相关API也可以很快的熟悉起来。看完前两章,对rdd,pairRdd操作比较熟悉了,自己写了demo,本地程序跑的非常愉快。

​ 这本书对API描写的很清楚,用了很大篇幅。不过它的缺点也在于此:没有提供很好的大局观。Spark编程不同于我们平常写的本地程序,这是要在分布式集群里运行的,首先对Spark的作业运行方式没有明确的阐述;其次对于分布式编程与本地编程没有明确,像Context各种类(SparkContext,SparkSession,SQLContext)没有明确定义使用范围,实际上是只能在driver上运行的。

学习资源

​ 除了这本实践类型的书,Spark的论文 英文版 中文版是必读的,读完之后可以看下Spark Internals ,对spark的体系架构讲解的很明白。还有一本《spark最佳实践》,我还没怎么看,有兴趣的也可以读读。

吐槽

​ Spark估计是我见过的版本最混乱的了,光是版本我就调了好几天,期间遇到各种各样的问题。

  1. kudu-spark2 没有scala2.10版本的包,如果你要使用kudu-spark2,就必须使用scala2.11,
  2. spark-streaming-kafka 不论是scala2.10还是2.11,都使用了一个Spark的叫Logging的类,而这个类在Spark1.5.2以后已经移除。可见 NoClassDefFoundError: org/apache/spark/Logging 讨论
  3. spark-streaming-kafka 存在对应Kafka版本的0-8和0-10两个包,然而这两个的createStream API签名都不一样,0-8与不带Kafka版本号的包签名一致。
  4. scala2.10跟2.11是不兼容的,这个需要我们注意,在引用包是都要用同一个scala版本的包
  5. Spark 2.1.1版本在版本说明上指定使用Scala2.11,对2.10的支持已经deprecated,然而由于2的原因我们实际上不能使用这个版本。

​ 由于以上的各种原因,组合来回,终于可以在Spark 2.1.1版本下本地运行成功了,这里提一下,spark-streaming-kafka-0-8是没有Logging类依赖的,可以使用。然而放到集群上,依然报错,问了一下,集群不支持Scala2.11

坑爹呢这是

​ 没办法只能把Scala换成2.10版本,由于前面已经踩过了n多的坑,这次直接将Spark版本换成1.5.2,对各种构造函数(SQLContext前面版本不支持SparkSession等)以及返回类型(DataSet换成DataFrame等)进行修改,本地启动没有问题,放到集群上顺利运行。

​ 目前还有一个问题就是在使用KuduContext进行更新删除数据时,需要使用SQLContext将List转换成DataFrame,但是前面经过各种转换Rdd已经变成了PairRdd,每个PairRdd对应的是kudu中不同的表,无法转换成单一Rdd。所以使用collect将数据收集起来了,在driver上运行,这是一个很坏的实践,会增大driver机内存爆掉的风险,目前还没有找到好的方法。

后记

​ 错误使人进步,我们也会写服务、工具去给别人使用,在设计的时候尽量避免API的混乱,遵从SOLID原则,给与设计更多的思考。后面会按照自己的理解也写一篇Spark简介,希望能帮到刚入门的各位。