2.3 Spark 概念

2.3.1 RDD

RDD是一个弹性分布式数据集,是一个只读的分区记录的集合,只能基于某个数据集或其他RDD上转换而来,因此具有高容错、低开销的特点。

2.3.2 Job

job 可以认为是我们在driver 或是通过spark-submit 提交的程序中一个action ,在我们的程序中有很多action 所有也就对应很多的jobs

2.3.3 Stage

stage是由DAGScheduler**根据宽窄依赖划分**spark任务所得到的一组可并行执行的task任务集合,存在依赖关系的stage之间是串行的,一个sparkJob可能产生多组stage。

  • stage

    • ResultStage
      • 在RDD的某些分区上应用函数来计算action操作的结果,对应DAG原理中createResultStage()创建的对象
    • ShuffleMapStage
      • ShuffleMapStage 是中间的stage,为shuffle生产数据。它们在shuffle之前出现。当执行完毕之后,结果数据被保存,以便reduce 任务可以获取到

        2.3.4 Task

        task是执行spark job 的逻辑单元,运行在executor的Cpu Core中
  • Task(shuffle操作发生后,那么Task会划分两种Task)

    • ShuffleMapTask
      • 上游数据叫做ShuffleMapTask,主要是用于将数据进行上游处理,为下游数据拉取做准备
      • 下游数据,主要是基于上游数据的结果集,其实ResultTask会根据元数据索引进行拉取数据文件,然后根据Key聚合内部所有的value值。

        2.3.5 Spark里kyro序列化了解多少?

        Spark的序列化 默认为org.apache.spark.serializer.JavaSerializer,可选org.apache.spark.serializer.KryoSerializer,实际上只要是org.apache.spark.serializer的子类就可以了,不过如果只是应用,大概你不会自己去实现一个的。
        序列化对于spark应用的性能来说,还是有很大影响的,在特定的数据格式的情况下,KryoSerializer的性能可以达到JavaSerializer的10倍以上,当然放到整个Spark程序中来考量,比重就没有那么大了,但是以Wordcount为例,通常也很容易达到30%以上的性能提升。而对于一些Int之类的基本类型数据,性能的提升就几乎可以忽略了。KryoSerializer依赖Twitter的Chill库来实现,相对于JavaSerializer,主要的问题在于不是所有的Java Serializable对象都能支持。
        需要注意的是,这里可配的Serializer针对的对象是Shuffle数据,以及RDD Cache等场合,而Spark Task的序列化是通过spark.closure.serializer来配置,但是目前只支持JavaSerializer。

        2.3.6 持久化

        spark通过catch和persist方法对结果进行一个持久化,persist方法共有5个参数,对应12个缓存级别,这12个级别分别从磁盘存储、内存存储、堆外内存存储、是否反序列化和备份数五个角度设定。其中catch使用的是Memory_Only,只在内存持久化。

        2.3.7 检查点

        spark通过checkPoint方法将RDD状态保存在高可用存储中,与持久化不同的是,它是对RDD状态的一个复制持久化,执行checkPoint后不再保存依赖链。此外,持久化存储的缓存当程序运行结束后就会被自动删除检查点保存的RDD状态只能手动清理。

        2.3.8 广播变量

        正常情况下spark为每个Task都复制了一份它需要的数据,如果有大量Task都需要用到一份相同的数据,这种做法就会导致一个节点Excutor(内含多个Task)从driver端拉取大量重复数据,占用网络IO和内存资源。使用广播变量后,Task会惰性加载数据,加载时,先在本地Excutor的BlockManager中寻找,如果找不到再到最近节点的BlockManager中查找,直到找到数据后将数据传输到本地存储起来,同一节点的多个Task就可以复用这份数据,大幅减少内存占用和IO时间。

        2.3.9 累加器

        spark提供了一个累加器用于在整个流程中额外执行一个MR任务,它可以在driver端被初始化发送给各个Task,然后在每个Task中为它添加数据,最终经过reduce将结果聚合后返回driver端。可以自定义累加器的类型,通过实现一个聚合方法来创建自定义累加器。除此之外spark2还支持特殊的累加器-收集器,它不需要执行reduce,会将数据原原本本存放在集合中返回。注意:如果累加操作在transform算子并且action算子有多个时,需要catch该转换算子,否则可能造成重复累加。

2.3.10 分区

2.3.10.1 概念

分区是RDD内部并行计算的一个计算单元,是RDD数据集的逻辑分片,分区的格式决定并行计算的粒度,分区的个数决定任务的个数。

2.3.10.2 作用

通过将相同的key放在相同的节点,避免不同节点聚合key时进行shuffle操作产生的网络IO;此外,事先分区好的数据在join时就可以只由另一张表shuffle,自身不shuffle,这常常用在大表join小表上。

2.3.10.3 默认分区器

HashPartitioner:将key的哈希值/分区数量进行分区可选分区器RangePartitioner:范围分区器,按照字典顺序或数字大小排序后/分区数量来分区

2.3.10.4 自定义分区器

通过实现get分区总数方法和get分区数方法,指定自定义规则的key分区方式;使用自定义分区器创建的RDD进行复杂的聚合或join操作效率更高。