Spark整理笔记一

本文深入解析了Spark的核心数据结构——RDD的特性与操作,探讨了其弹性分布式数据集的设计理念及其实现机制。此外,还详细介绍了Spark作业的运行流程、集群管理器的选择,以及RDD的依赖关系对任务调度的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spark: Master Workder

Yarn: ResourceManager  (ApplicationMaster) NodeManager Container(用于可插拔计算框架)

 

Spark 有三大数据结构: RDD,广播变量,累加器

 

RDD: Resilient Distributed Dataset 弹性分布式数据集
    描述:
        是Spark计算的基石,为用户屏蔽了底层对数据的复杂抽象和处理,为用户提供了一组方便的数据转换与求值方法
    特征: 不可变,可分区,弹性
        不可变:生成新的RDD,而不是对原有的RDD改变
        可分区:可并行运行
        弹性:
            存储的弹性:内存与磁盘的自动切换
            容错的弹性:数据丢失可以自动恢复(数据丢失则查找上一个RDD的数据)
            计算的弹性:计算出错重试机制(mapreduce默认重试4次)
            分片的弹性:根据需要重新分片
    RDD做了什么:
        RDD的创建,RDD的转换,RDD的缓存,RDD的行动,RDD的输出
        RDD是懒执行,主要两大类是RDD的转换和RDD的行动。RDD的行动算子不调用就不会执行前面的步骤。调用一次则从头开始计算一次,如果调用的多可以用持久化。

    RDD的创建:
        方式:
            1 从内存中的对象集合中创建(也称并行化一个集合):

                          val config: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Hello")

                          val sc = new SparkContext(config)

                          sc.parallelize(1 to 10) 

                          sc.makeRDD(1 to 10) 
            2 从外部存储创建(eg:HDFS); sc.textFile(inputPath)
            3 从其他RDD转换
        从集合中创建有两种方式:
            parallelize(真的实现) 和  makeRDD
        由外部存储系统的数据集创建,包括本地的文件系统,HDFS,Cassandra,HBase等

    转换和动作:
        转换(transformation惰性):从现有RDD生成新的RDD
        动作(action立刻):触发对RDD的计算并对计算结果执行某种操作,要么返回用户,要么保存到外部存储器
        
    按键来为键值对RDD仅限聚合操作的三个主要转换函数:reduceByKey(),foldByKey(),aggregateByKey()
    
    持久化:
        tuples.cache(),大规模作业来说可以节省客观的时间,但只能由同一应用的作业来读取。若executor没有足够内存来存储RDD分区,计算不会失败,会根据需要重新计算分区
        saveAsTextFile(),saveAsHadoopFile()可以存储到外部存储器,被多个应用使用
        提供不同级别的持久化:
            persist()并指定StorageLevel
            MEMORY_ONLY(默认):常规表示方法
            MEMORY_ONLY_SER:通过分区中的元素序列化为字节数组来实现,比默认的多了一份CPU开销,但减少内存,还能减少垃圾回收的压力
            MEMORY_AND_DISK:不适合存储在内存,就将其溢出到磁盘
            MEMORY_AND_DISK_SER:如果序列化数据集的大小不适合保存到内存中,就溢出到磁盘
            
    序列化:
        数据序列化  和  函数序列化(闭包函数)
        数据:Kryo(高效的通用Java序列化库)
            conf.set("spark.serializer","org.apache.spark.serializer.KryoSerializer")
            优化:如果使用前,先在Kryo中对这些类进行注册,可以提高性能
                class Cust extends KryoRegistrator{...}
                conf.set("spark.kryo.registrator","Cust")
        函数:若不可序列号,应该在开发初期就发现它
        
    共享变量:分布式只读共享变量
        广播变量(broadcast variable):
            在经过序列化后被发送给各个executor,然后缓存在那里,以便后期任务可以在需要时访问,为单向传播,即从driver到任务,因此无法被更新。
            sc.broadcast()
            
        累加器:   分布式只写共享变量 
            在任务中只能对它做假发的共享变量。当作业完成后,driver程序可以检索累加器的最终值。
            sc.accumulator(0)
        
    剖析Spark作业运行机制:
        最高层:driver(任务调度,一般不由集群管理器管理的客户端运行),executor(专属应用,集群的计算机上)
        执行action操作,内部看:
            1 SparkContext 调用了 runJob()
             调度程序:
                2 DAG调度程序(DAGScheduler):
                    把作业分成若干阶段(stages),这些阶段构成了一个完整的DAG,然后把每个阶段的任务集合提交给任务调度
                    作业类型:
                        shuffle map任务  和result 任务
                3 任务调度程序(TaskScheduler):把每个阶段中的任务提交到集群
                    在斟酌位置偏好的同时构建任务到executor的映射。
                    接着讲任务分配具有可用内核的executor
                    executor完成后分配更多任务,直至全部完成(默认每个任务一个内核,可修改)
                        分配顺序:进程本地任务,节点本地任务,机架本地任务,最后任意分配
                    
            4  调度程序后端启动,向Executor(SchedulerBackend)后端发送远程启动任务消息
            
            5  Executor后端接收
            6  执行Executor
            7  ShuffleMapTask or ResultTask
                Executor:
                    a 任务确保任务的JAR包和文件依赖关系是最新的
                    b 反序列化发过来的一部分序列号代码
                    c 执行代码,因为任务运行在与executor相同的JVM中,因此任务的启动没有进程开销
            
            8 执行后,以状态更新消息的形式,将driver返回序列号后的执行结果。
                shuffle map 任务返回的是一些可以让下一个阶段检索其输出分区的消息
                result 任务返回其运行的分区的结果值。
            9 driver 将结果收集起来,并把最终结果返回给用户的程序
    
        shuffle map任务:
            像MapReduce中的shuffle的map端部门。每个任务在一个RDD分区上运行计算,并根据分区函数把输出写入一组新的分区中,以允许在后面的阶段中取用。shuffle map任务运行在除最终阶段之外的其他所有阶段中。
    
        result 任务:
            运行在最终阶段,并将结果返回给用户程序。每个result任务在它自己的RDD分区上运行计算,然后把最终结果发送回driver,再由driver将每个分区的计算结果汇集成最终结果
        
        最简单的Spark作业只有一个由result任务构成阶段
        
        复杂的作业设计到分组操作,回要求一个或多个shuffle阶段
        
        Spark的shuffle实现将其输出写入本地磁盘的分区文件中(即使对内存中的RDD也一样),并且这些文件将由下一个阶段的RDD读取
        
    集群管理器:
        本地模式,独立模式,Mesos模式,YARN模式
        
    宽依赖:
        父RDD每个分区的数据可能被多个子RDD分区使用,子RDD分区通常对应所有的父RDD分区
            1 一个父RDD分区 对应 所有的子RDD分区 (没有co-patitioned过的join)
            2 一个父RDD分区 对应 非全部的多个RDD分区 (groupByKey)
            
    窄依赖:
        父RDD每个分区的只被一个子RDD分区使用,子RDD通常对应多个父RDD分区
            1 一个子RDD分区 对应 一个父RDD分区 (filter,map)
            2 一个子RDD分区 对应 多个父RDD分区 (co-patitioned过的join)
    
    优缺点:
        宽依赖:有shuffle,要跨网络去拉取资源,耗资源;当子RDD需要重算时,会重算所有父RDD分区数据
        窄依赖:一个节点内完成转化,快速;当子RDD需要重算时,只需计算对应的一个父RDD数据即可
    
    宽依赖:reduceByKey,groupByKey,combineByKey,sortByKey,join(no copartition)
    窄依赖:filter,mao,flatmao,mapPartitions
    
    Spark的作业(job)比MapReduce的作业更通用,因为Spark作业是由任意的多阶段(stages)有向无环图(DAG)构成,其中每个阶段大致相当于MapReduce中的map阶段或者reduce阶段。这些阶段又被Spark分成多个任务(task),并行运行在分布于集群中的RDD分区上,
    
    Spark作业始终运行在应用(application)上下文(用SparkContext实例来表示)中,它提供了RDD分组以及共享变量
    

任务划分:

    RDD任务切分中间分为:Applicatition,Job,Stask,Task

        Applicatition:初始化一个SparkContext,即生成一个Applicatition

       Job:一个Actition算子就会生成一个Job

      Stage:根据RDD之间的依赖关系的不同将Job划分为不同的Stage,遇到一个宽依赖则划分为一个Stage

      Task:Stage是一个TaskSet,将Stage划分的结果发送到不同的Executor执行,即为一个Task

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值