• Apache Spark源码走读之1 -- Spark论文阅读笔记


    欢迎转载,转载请注明出处,徽沪一郎。

    楔子

    源码阅读是一件非常容易的事,也是一件非常难的事。容易的是代码就在那里,一打开就可以看到。难的是要通过代码明白作者当初为什么要这样设计,设计之初要解决的主要问题是什么。

    在对Spark的源码进行具体的走读之前,如果想要快速对Spark的有一个整体性的认识,阅读Matei Zaharia做的Spark论文是一个非常不错的选择。

    在阅读该论文的基础之上,再结合Spark作者在2012 Developer Meetup上做的演讲Introduction to Spark Internals,那么对于Spark的内部实现会有一个比较大概的了解。

    有了上述的两篇文章奠定基础之后,再来进行源码阅读,那么就会知道分析的重点及难点。

    基本概念(Basic Concepts)

    RDD - resillient distributed dataset 弹性分布式数据集

    Operation - 作用于RDD的各种操作分为transformation和action

    Job - 作业,一个JOB包含多个RDD及作用于相应RDD上的各种operation

    Stage - 一个作业分为多个阶段

    Partition - 数据分区, 一个RDD中的数据可以分成多个不同的区

    DAG - Directed Acycle graph, 有向无环图,反应RDD之间的依赖关系

    Narrow dependency - 窄依赖,子RDD依赖于父RDD中固定的data partition

    Wide Dependency - 宽依赖,子RDD对父RDD中的所有data partition都有依赖

    Caching Managenment -- 缓存管理,对RDD的中间计算结果进行缓存管理以加快整体的处理速度

    编程模型(Programming Model)

    RDD是只读的数据分区集合,注意是数据集

    作用于RDD上的Operation分为transformantion和action。 经Transformation处理之后,数据集中的内容会发生更改,由数据集A转换成为数据集B;而经Action处理之后,数据集中的内容会被归约为一个具体的数值。

    只有当RDD上有action时,该RDD及其父RDD上的所有operation才会被提交到cluster中真正的被执行。

    从代码到动态运行,涉及到的组件如下图所示。

     

    演示代码

    
    val sc = new SparkContext("Spark://...", "MyJob", home, jars)
    val file = sc.textFile("hdfs://...")
    val errors = file.filter(_.contains("ERROR"))
    errors.cache()
    errors.count()
    
    

    运行态(Runtime view)

    不管什么样的静态模型,其在动态运行的时候无外乎由进程,线程组成。

    用Spark的术语来说,static view称为dataset view,而dynamic view称为parition view. 关系如图所示

    在Spark中的task可以对应于线程,worker是一个个的进程,worker由driver来进行管理。

    那么问题来了,这一个个的task是如何从RDD演变过来的呢?下节将详细回答这个问题。

    部署(Deployment view)

    当有Action作用于某RDD时,该action会作为一个job被提交。

    在提交的过程中,DAGScheduler模块介入运算,计算RDD之间的依赖关系。RDD之间的依赖关系就形成了DAG。

    每一个JOB被分为多个stage,划分stage的一个主要依据是当前计算因子的输入是否是确定的,如果是则将其分在同一个stage,避免多个stage之间的消息传递开销。

    当stage被提交之后,由taskscheduler来根据stage来计算所需要的task,并将task提交到对应的worker.

    Spark支持以下几种部署模式1)standalone 2)Mesos 3) yarn. 这些部署模式将作为taskscheduler的初始化入参。

    RDD接口(RDD Interface)

    RDD由以下几个主要部分组成

    1. partitions --    partition集合,一个RDD中有多少data partition
    2. dependencies -- RDD依赖关系
    3. compute(parition) -- 对于给定的数据集,需要作哪些计算
    4. preferredLocations --  对于data partition的位置偏好
    5. partitioner -- 对于计算出来的数据结果如何分发

    缓存机制(caching)

    RDD的中间计算结果可以被缓存起来,缓存先选Memory,如果Memory不够的话,将会被写入到磁盘中。

    根据LRU(last-recent update)来决定哪先内容继续保存在内存,哪些保存到磁盘。

    容错性(Fault-tolerant)

    从最初始的RDD到衍生出来的最后一个RDD,中间要经过一系列的处理。那么如何处理中间环节出现错误的场景呢?

    Spark提供的解决方案是只对失效的data partition进行事件重演,而无须对整个数据全集进行事件重演,这样可以大大加快场景恢复的开销。

    RDD又是如何知道自己的data partition的number该是多少?如果是hdfs文件,那么hdfs文件的block将会成为一个重要的计算依据。

    集群管理(cluster management)

    task运行在cluster之上,除了spark自身提供的standalone部署模式之外,spark还内在支持yarn和mesos.

    Yarn来负责计算资源的调度和监控,根据监控结果来重启失效的task或者是重新distributed task一旦有新的node加入cluster的话。

    这一部分的内容需要参考yarn的文档。

    小结

    在源码阅读时,需要重点把握以下两大主线。

    • 静态view 即 RDD, transformation and action
    • 动态viewlife of a job, 每一个job又分为多个stage,每一个stage中可以包含多个rdd及其transformation,这些stage又是如何映射成为task被distributed到cluster中

    参考资料(reference)

    1. Introduction to Spark Internals http://files.meetup.com/3138542/dev-meetup-dec-2012.pptx
    2. Resilient Distributed Datasets: A Fault-tolerant Abstraction for In-Memory Cluster Computing  https://www.usenix.org/system/files/.../nsdi12-final138.pdf
    3. Lightning-Fast Cluster Computing with Spark and Shark   http://www.meetup.com/TriHUG/events/112474102/
  • 相关阅读:
    根据CPU核数合理设置线程池大小
    jvm类加载的过程
    springboot2.x整合redis实现缓存(附github链接)
    记录一次坎坷的debug之旅,NUXT框架页面多开假死现象,NUXT刚开始可以访问,突然就访问无响应,并且前后端均未出现任何报错提示:现在是早晨4点35分
    hibernate用Query.setFirstResult和Query.setMaxResults分页时,传入的manresults不能为0,否则解析后的sql会去查全表数据
    工作时发现oracle的分页查询的数据会重复,进行分析并给出解决方式
    看别人的代码是进步最快的方式
    关于电磁炉使用时造成的电磁场导致洗衣机等电器失效的情况总结
    关于在项目中创建一个新的线程之后需要将线程持有的数据库连接对象归还的思考
    Oracle分页和mysql分页的区别
  • 原文地址:https://www.cnblogs.com/hseagle/p/3664933.html
Copyright © 2020-2023  润新知