Spark运行调试方法与学习资源汇总
最近,在学习和使用Spark的过程中,遇到了一些莫名其妙的错误和问题,在逐个解决的过程中,体会到有必要对解决上述问题的方法进行总结,以便能够在短时间内尽快发现问题来源并解决问题,现与各位看官探讨学习如下:
解决spark运行调试问题的四把“尖刀”:
1、Log
包括控制台日志、主从节点日志、HDFS日志等。
许多错误可以通过日志,直接对错误类型、错误来源进行准确定位,因此,学会读取和分析Log是解决问题的第一步。
2、Google
确定错误类型和原因后,就可以使用Google在SparkUserList、GoogleGroup等各类Spark学习社区和论坛进行求助,而大部分问题都是可以找到答案的。
3、官网配置文档
大部分问题都是配置问题引起的,如何准确配置,需要结合官方说明文档进行配置,而其中的TuningSpark内容,也是每个Spark实践者必须了解和掌握的,推荐精读:
TuningSpark(内存调优):
http:
//spark.apache.org/docs/1.0.0/tuning.html
SparkConfiguration(基本配置):
http:
//spark.apache.org/docs/1.0.0/configuration.html
4、官网Example
各个子项目都有对应的Example和源码,可以从源码的src子文件夹里找到,而在每个子项目的官网说明上也有相应的代码示例,也可以作为参考。
这4个方法是解决问题的第一位要素,特别地,要会通过Log反推错误来源,定位故障原因,然后第一时间想到谷歌,把错误关键词粘贴查找寻求解答。
而大部分人的问题其实主要都是配置问题,1和2其实就能解决了。
3和4主要用来模仿学习,照猫画虎,学以致用,不成功便成仁。
交流和互动也很重要,把握国内Spark研究的前沿,就要善于利用和挖掘各类互联网资源,这里,推荐一些博客、微博、QQ学群供大家参考学习:
知名博主:
徽沪一郎:
fxjwind:
张包峰:
高彦杰:
saisai_shao:
http:
//jerryshao.me/
微博大牛:
hashjoin,Databricks大数据公司创始人之一,UCBerkeleyAMPLab:
Andrew-Xia:
CrazyJvm:
明风Andy,淘宝技术部,数据挖掘与计算团队负责人:
saisai_shao:
连城:
张包峰:
王联辉:
徽沪一郎:
Spark学习资料
FastDataProcessingwithSpark,
Scala学习资料:
快学Scala,
ScalaCookbook,
Scala编程,
Spark论文:
NSDI-2012,
[博士论文]MateiZaharia,
QQ群:
Spark零基础学习@367106111
Spark快速理解
BLOG:
更多云计算相关项目快速理解文档
==是什么==
目标Scope(解决什么问题)
在大规模的特定数据集上的迭代运算或重复查询检索
官方定义
aMapReduce-likeclustercomputingframeworkdesignedforlow-latencyiterativejobsandinteractiveusefromaninterpreter
个人理解
首先,MapReduce-like是说架构上和多数分布式计算框架类似,Spark有分配任务的主节点(Driver)和执行计算的工作节点(Worker)
其次,Low-latency基本上应该是源于Worker进程较长的生命周期,可以在一个Job过程中长驻内存执行Task,减少额外的开销
然后对interative重复迭代类查询运算的高效支持,是Spark的出发点了。
最后它提供了一个基于Scala的Shell方便交互式的解释执行任务
==如何实现==
核心思路,架构
RDD:
Spark的核心概念是RDD(resilientdistributeddataset),指的是一个只读的,可分区的分布式数据集,这个数据集的全部或部分可以缓存在内存中,在多次计算间重用。
Lineage:
利用内存加快数据加载在众多的其它的In-Memory类数据库或Cache类系统中也有实现,Spark的主要区别在于它处理分布式运算环境下的数据容错性(节点实效/数据丢失)问题时采用的方案。
为了保证RDD中数据的鲁棒性,RDD数据集通过所谓的血统关系(Lineage)记住了它是如何从其它RDD中演变过来的。
相比其它系统的细颗粒度的内存数据更新级别的备份或者LOG机制,RDD的Lineage记录的是粗颗粒度的特定数据变换(Transformation)操作(filter,map,joinetc.)行为。
当这个RDD的部分分区数据丢失时,它可以通过Lineage获取足够的信息来重新运算和恢复丢失的数据分区。
这种粗颗粒的数据模型,限制了Spark的运用场合,但同时相比细颗粒度的数据模型,也带来了性能的提升。
总之,Spark的核心思路就是将数据集缓存在内存中加快读取速度,同时用lineage关联的RDD以较小的性能代价保证数据的鲁棒性。
适用领域
正如其目标scope,Spark适用于需要多次操作特定数据集的应用场合。
需要反复操作的次数越多,所需读取的数据量越大,受益越大,数据量小但是计算密集度较大的场合,受益就相对较小。
细节
使用内存缓存数据集快在哪里?
主要是几个方面:
首先是磁盘IO,其次数据的序列化和反序列化的开销也节省了,最后相对其它内存数据库系统,粗颗粒度的内存管理机制减小了数据容错的代价(如典型的数据备份复制机制)
==相关项目==
上下游项目
DiscretizedStreams(Sparkstreaming)
构建在Spark上处理Stream数据的框架,基本的原理是将Stream数据分成小的时间片断(几秒),以类似batch批量处理的方式来处理这小部分数据。
个人理解构建在Spark上的原因大概是因为Spark的低延迟执行引擎(100ms+)勉强可以用于实时处理,而Spark的核心理念数据重用和流式数据处理本身并没有直接的交集,相反个人感觉流式数据的无穷连续性的特性一定程度上和数据重用是冲突的。
相比基于Record的其它处理框架(如Storm),RDD数据集更容易做高效的容错处理。
此外小批量处理的方式使得它可以同时兼容批量和实时数据处理的逻辑和算法。
方便了一些需要历史数据和实时数据联合分析的特定应用场合。
Shark(HiveonSpark)
Shark基本上就是在Spark的框架基础上提供和Hive一样的HiveQL命令接口,为了最大程度的保持和Hive的兼容性,Shark使用了Hive的API来实现queryParsing和LogicPlangeneration,最后的PhysicalPlanexecution阶段用Spark代替HadoopMapReduce。
通过配置Shark参数,Shark可以自动在内存中缓存特定的RDD,实现数据重用,进而加快特定数据集的检索。
同时,Shark通过UDF用户自定义函数实现特定的数据分析学习算法,使得SQL数据查询和运算分析能结合在一起,最大化RDD的重复使用。
类似项目
Twister:
http:
//www.iterativemapreduce.org大概的意思也是通过Cache数据,实现迭代的MapReduce过程中的数据重用,不过它的模型貌似相对简单些,大致是通过拓展MapReduceAPI,分发管理缓存数据,然后通过自己的Daemon进程管理和分配MapReduceTask到Cache对应的节点上,容错性和计算模型方面没有Shark的RDD来得精巧和通用。
Haloop:
和Twister类似,修改扩展了MapReduce框架,增加了循环逻辑和DataCaching
==相关文献==
http:
//spark-project.org/项目首页
http:
//shark.cs.berkeley.edu/shark项目主页
Paper论文
http:
//www.cs.berkeley.edu/~matei/papers/2012/nsdi_spark.pdf
==其它==
主要实现和编程接口基于Scala
Spark的YARN模式部署
Spark可以通过SBT(ScalaBuildTool)或者Maven来编译,官方提供的二进制安装文件是用Maven编译。
1:
Spark的编译
Spark可以通过SBT(ScalaBuildTool)或者Maven来编译,官方提供的二进制安装文件是用Maven编译,如果是要在YARN集群上运行的话,还需要再用SBT编译一下,生成YARNclient端使用的jar包;最好是直接对源码使用SBT进行编译而生成YARNclient端使用的jar包。
笔者在测试过程中,对Maven编译过的Spark进行SBT二次编译后,在运行部分例子的时候有错误发生。
A:
Maven编译
笔者使用的环境曾经编译过Hadoop2.2.0(参见hadoop2.2.0源码编译(CentOS6.4)),所以不敢确定Maven编译过程中,Spark是不是需要编译Hadoop2.2.0中使用的部分底层软件(看官方资料是需要Protobuf2.5)。
除了网络下载不给力而不断的中止、然后重新编译而花费近1天的时间外,编译过程还是挺顺利的。
maven编译时,首先要进行设置Maven使用的内存项配置:
export MAVEN_OPTS="-Xmx2g-XX:
MaxPermSize=512M-XX:
ReservedCodeCacheSize=512m"
然后用Maven编译:
mvn -Pnew-yarn -Dhadoop.version=2.2.0 -Dyarn.version=2.2.0 -DskipTestspackage
参考文档:
BuildingSparkwithMaven
B:
SBT编译
Spark源码和二进制安装包都绑定了SBT。
值得注意的是,如果要使用Scala进行Spark应用开发,必须使用和Spark版本相对应版本的Scala,如:
Spark0.8.1对应的Scala2.9.3。
对于不匹配的Scala应用开发可能会不能正常工作。
SBT编译命令:
SPARK_HADOOP_VERSION=2.2.0 SPARK_YARN=true ./sbt/sbtassembly
二种编译都是在Spark根目录下运行。
在SBT编译过程中如果网络不给力,手工中断编译(ctrl+z)后要用kill-9将相应的进程杀死后,然后再重新编译,不然会被之前的sbt进程锁住而不能重新编译。
2:
Spark运行
Spark可以单独运行,也可以在已有的集群上运行,如AmazonEC2、ApacheMesos、HadoopYARN。
下面用Spark自带的例程进行测试,运行的时候都是在Spark的根目录下进行。
如果需要知道运行更详细的信息,可以使用log4j,只要在根目录下运行:
cpconf/log4j.properties.template conf/log4j.properties
A:
本地运行
./run-exampleorg.apache.spark.examples.SparkPi local
也可以多线程方式运行,下面的命令就是开4个线程。
./run-exampleorg.apache.spark.examples.SparkPi local[4]
B:
YARN集群
启动Hadoop2.2.0集群
确保环境变量HADOOP_CONF_DIR或YARN_CONF_DIR已经设置
在YARN集群中运行Spark应用程序的命令:
SPARK_JAR= ./spark-classorg.apache.spark.deploy.yarn.Client \
--jar \
--class \
--args \
--num-workers \
--master-class
--master-memory \
--worker-memory \
--worker-cores \
--name \
--queue \
--addJars \
--files \
--archives
例1计算PI,可以看出程序运行时是先将运行文件上传到Hadoop集群的,所以客户端最好是和Hadoop集群在一个局域网里。
SPARK_JAR=./assembly/target/scala-2.9.3/spark-assembly-0.8.1-incubating-hadoop2.2.0.jar \
./spark-class org.apache.spark.deploy.yarn.Client \
--jar examples/target/scala-2.9.3/spark-examples-assembly-0.8.1-incubating.jar \
--class org.apache.spark.examples.SparkPi \
--args yarn-standalone \
--num-workers 3 \
--master-memory 2g \
--worker-memory 2g \
--worker-cores 1
例2计算TC
SPARK_JAR=./assembly/target/scala-2.9.3/spark-assembly-0.8.1-incubating-hadoop2.2.0.jar \
./spark-class org.apache.spark.deploy.yarn.Client \
--jar examples/target/scala-2.9.3/spark-examples-assembly-0.8.1-incubating.jar \
--class org.apache.spark.examples.SparkTC \
--args yarn-standalone \
--num-workers 3 \
--master-memory 2g \
--worker-memory 2g \
--worker-cores 1
点击TrackingUI中的相应链接可以查看Spark的运行信息:
SparkonYARN客户端模式作业运行全过程分析
博客地址:
文章标题:
《SparkonYARN客户端模式作业运行全过程分析》
本文链接:
Hadoop
、Hive、Hbase、Flume等QQ交流群:
138615359(已满),请加入新群:
149892483
《SparkonYARN集群模式作业运行全过程分析》
《SparkonYARN客户端模式作业运行全过程分析》
《
Spark
Standalone模式作业运行全过程分析》(未发布)
在前篇文章中我介绍了 Spark onYARN集群模式(yarn-cluster)作业从提交到运行整个过程的情况(详情见 《SparkonYARN集群模式作业运行全过程分析》 ),我们知道
Spark
onyarn有两种模式:
yarn-cluster和yarn-client。
这两种模式作业虽然都是在yarn上面运行,但是其中的运行方式很不一样,今天我就来谈谈SparkonYARNyarn-client模式作业从提交到运行的过程剖析。
和yarn-cluster模式一样,整个程序也是通过spark-submit脚本提交的。
但是yarn-client作业程序的运行不需要通过Client类来封装启动,而是直接通过反射机制调用作业的main函数。
下面就来分析:
1、通过SparkSubmit类的launch的函数直接调用作业的main函数(通过反射机制实现),如果是集群模式就会调用Client的main函数。
2、而应用程序的main函数一定都有个SparkContent,并对其进行初始化;
3、在SparkContent初始化中将会依次做如下的事情:
设置相关的配置、注册MapOutputTracker、BlockManagerMaster、BlockManager,创建taskScheduler和dagScheduler;其中比较重要的是创建taskScheduler和dagScheduler。
在创建taskScheduler的时候会根据我们传进来的master来选择Scheduler和SchedulerBackend。
由于我们选择的是yarn-client模式,程序会选择 YarnClientClusterScheduler和
Yarn
ClientSchedulerBackend,并将YarnClientSchedulerBackend的实例初始化YarnClientClusterScheduler,上面两个实例的获取都是通过反射机制实现的,YarnClientSchedulerBackend类是CoarseGrainedSchedulerBackend类的子类,YarnClientClusterScheduler是TaskSchedulerImpl的子类,仅仅重写了TaskSchedulerImpl中的getRackForHost方法。
4、初始化完taskScheduler后,将创建dagScheduler,然后通过taskScheduler.start()启动taskScheduler,而在taskScheduler启动的过程中也会调用SchedulerBackend的start方法。
在SchedulerBackend启动的过程中将会初始化一些参数,封装在ClientArguments中,并将封装好的ClientArguments传进Client类中,并client.runApp()方法获取ApplicationID。
5、client.runApp里面的做是和前面 客户端进行操作 那节类似,不同的是在里面启动是ExecutorLauncher(yarn-cluster模式启动的是ApplicationMaster)。
6、在ExecutorLauncher里面会初始化并启动amClient,然后向ApplicationMaster注册该Application。
注册完之后将会等待driver的启动,当driver启动完之后,会创建一个MonitorActor对象用于和CoarseGrainedSchedulerBackend进行通信(只有事件AddWebUIFilter他们之间才通信,Task的运行状况不是通过它和CoarseGrainedSchedulerBackend通信的)。
然后就是设置addAmIpFilter,当作业完成的时候,ExecutorLauncher将通过amClient设置Application的状态为FinalApplicationStatus.SUCCEEDED。
7、分配Executors,这里面的分配逻辑和yarn-cluster里面类似,就不再说了。
8、最后,Task将在CoarseGrainedExecutorBackend里面运行,然后运行状况会通过Akka通知CoarseGrainedScheduler,直到作业运行完成。
9、在作业运行的时候,YarnClientSchedulerBackend会每隔1秒通过client获