• spark概述


    Spark背景:MapReduce局限性

    MapReduce框架局限性

    1、仅支持Map和Reduce两种操作,提供给用户的只有这两种操作

    2、处理效率低效

        Map中间结果写磁盘,Reduce写HDFS,多个MR之间通过HDFS交换数据

        任务调度和启动开销大:mr的启动开销一,客户端需要把应用程序提交给resourcesManager,resourcesManager去选择节点去运行,快的话几秒钟,慢的话1分钟左右,开销二,maptask和reducetask的启动,当他俩被resourcesManager调度的时候,会先启动一个container进程,然后让他俩运行起来,每一个task都要经历jvm的启动,销毁等,这两点就是mr启动开销

        无法充分利用内存

    3、Map端和Reduce端均需要排序:map和Reduce是都需要进行排序的,但是有的程序完全不需要排序(比如求最大值求最小值,聚合等),所以就造成了性能的低效

    4、不适合迭代计算(如机器学习、图计算等),交互式处理(数据挖掘)和流式处理(点击日志分析):因为任务调度和启动开销大,所以不适合交互式处理,比如你启动要一分钟,任务调度要几分钟,我得等半天,这不适合

    MapReduce编程不够灵活

    map和reduce输入输出类型格式限制死了,可尝试scala函数式编程语言

    背景:框架多样化

    现有的各种计算框架各自为战

    批处理:MapReduce、Hive、Pig

    流式计算:Storm

    交互式计算:presto,Impala

    能否有一种灵活的框架可同时进行批处理、流式计算、交互式计算等?

    大数据时代,最重要的两种技术

    一个是存储的技术,如hdfs,hbase,一个是计算的技术,如上述说的MR、Storm、Impala

    Spark特点

    1、高效(比MapReduce快10~100倍)

      内存计算引擎,提供Cache机制来支持需要反复迭代计算或者多次数据共享,减少数据读取的IO开销

      DAG引擎,这种引擎的特点是,不同任务之间互相依赖,减少多次计算之间中间结果写到HDFS的开销

      使用多线程池模型来减少task启动开稍(特指MR中每个task都要经历JVM启动运行销毁操作,Spark的做法是,启动一些常驻的进程,在进程内部会有多个线程去计算task,来一个task,计算task,并回收线程,以此循环,这样就没有JVM的开销),shuffle过程中避免不必要的sort操作以及减少磁盘IO操作

    2、易用

      提供了丰富的API,支持Java,Scala,Python和R四种语言

      代码量比MapReduce少2~5倍

    3、与Hadoop集成

      读写HDFS/Hbase

      与YARN集成

    Spark核心概念—RDD

    RDD:Resilient Distributed Datasets,弹性分布式数据集

    数据集与分布式:

      分布在集群中的只读对象集合(由多个Partition构成)

      可以存储在磁盘或内存中(多种存储级别)

    弹性:

      通过并行“转换”操作构造,数据通过一些转换方式,在转换成其他数据集

      失效后自动重构,数据有自恢复能力

    大白话:

    rdd丢了,要用该rdd的时候,才会重构,不是丢掉的时候去重构

    rdd有三个分区,比如partition1丢了,就去重构partition1,其他分区不会重构

    rdd包含两部分,数据部分,元信息部分,元信息包含有哪些分区,分区放在哪些地点,分区的父分区id,及如何从父分区生成该分区(如map算子),元信息放在一个中心节点,当重构后,名字什么的元信息是不变的,如果中心节点挂掉,那整个程序就失败,也就无所谓rdd元信息丢不丢了

    rdd的个数:

    如果文件是在hdfs上的,那么hdfs上有多少个block,就有多少个rdd

    如果源数据是在内存里的,那么就可以随意指定分区数

    RDD基本操作(operator)

    Transformation

      可通过Scala集合或者Hadoop数据集构造一个新的RDD

      通过已有的RDD产生新的RDD

      举例:map, filter,groupBy,reduceBy

    Action

      通过RDD计算得到一个或者一组值

      举例:count,reduce,saveAsTextFile

    Spark RDD cache/persist

    Spark RDD Cache

      允许将RDD缓存到内存中或磁盘上,以便于重用

      Spark提供了多种缓存级别,以便于用户根据实际需求进行调整

    通过名字就大概知道对应的是什么存储策略,其中,DISK_ONLY_2指的是只存储在磁盘,在其他节点上额外存储一份

    不指定的话,默认是NONE,就是不存储,指定了后才存储

    带SER的表示对数据进行压缩,优点是省内存,缺点是,取数据的时候需要解压

    RDD cache使用
    val data = sc.textFile(“hdfs://nn:8020/input”)
    data.cache() //实际上是data.persist(StorageLevel.MEMORY_ONLY)
    //data.persist(StorageLevel.DISK_ONLY_2)

    RDD Transformation & Action

    接口定义方式不同

      Transformation:RDD[X] --> RDD[Y]

      Action: RDD[X] --> Z (Z不是一个RDD, 可能是基本类型,数组等)

    惰性执行(Lazy Execution)

      Transformation只会记录RDD转化关系,并不会触发计算,rdd[x] transfer到rdd[y] ,并不会生成一个结果,数据也不会变化,而是把计算过程记录下来,到执行action的时候,才会计算最终rdd

      Action是触发程序执行(分布式)的算子

    spark运行模式

    程序执行流程

    如上述代码,resultRdd的生成过程会产生四个RDD,前面三个RDD的分区是一对一的关系,第三个到第四个则是多对一,这里有一种说法,叫做宽依赖(一个分区依赖前面多个分区)和窄依赖

    提交Spark程序(运行在YARN上)

    export YARN_CONF_DIR=/opt/hadoop/yarn-client/etc/hadoop
    bin/spark-submit 
    --master yarn-cluster  
    --class com.hulu.examples.SparkPi 
    --name sparkpi 
    --driver-memory 2g 
    --driver-cores 1 
    --executor-memory 3g 
    --executor-cores 2 
    --num-executors 2 
    --queue spark 
    --conf spark.pi.iterators=500000 
    --conf spark.pi.slices=10 
    $FWDIR/target/scala-2.10/spark-example-assembly-1.0.jar

    --master yarn-cluster,指定启动在那种模式,如果是本地,则local[k]

    程序架构

    下面指的是跑在yarn上:

    上面刚才的代码就会运行在driver上,driver可以认为是spark的context,这里还有另外一个角色,就是executor,spark为了加速程序的运行,它会预先启动一些常驻内存的进程,这些进程上可以运行任务,这些进程就是executor,他跟mr不一样,mr是当我有一个任务的时候,才会启动一个jvm去计算这个任务

    driver可以把任务分解发到给executor,executor去执行这些任务,执行完后,executor空闲出来,driver就又可以发送任务给executor,这样就省出了jvm的启动开销

    executor是一个分布式执行的进程,在不同的物理节点上,会存在多个executor

    元信息全部存放在driver上,rdd的数据信息是存放在executor上的,executor上面有一个cache,在这个内存里存储了rdd的每一个分区的数据,如果我指定了把这个rdd缓存起来,那么这里就会被driver记录我这个rdd存放在哪个executor上

    数据信息存放在executor上的cache(mem_only)上, 或者exec那个node的disk(disk_only)上

    Spark运行模式

    local(本地模式)

      什么是本地模式?将Spark应用以多线程方式,所有executor都是跑在一个节点的一个进程里面的,每一个executor都是一个线程,直接运行在本地,便于调试

      本地模式分类:

        local:只启动一个executor

        local[K]:启动K个executor

        local[*]:启动跟cpu数目相同的executor

    standalone(独立模式)

      独立运行在一个集群中

      standalone是spark自己提供的,在这种模式里,spark自己有一个master程序。在master程序里,它会管理很多worker节点,在worker节点里面,他的driver和executor都是跑在对应的worker之上的 

    YARN/mesos

      运行在资源管理系统上,比如YARN或mesos,上面那个架构就是yarn运行模式

      yarn这种,driver和executor都是跑在yarn的container里面的,就是跑在每一个nodemanager之上的

      Spark On YARN存在两种模式

        yarn-client

        yarn-cluster

    程序运行模式:独立(Standlone)模式

    standalone中,它有一个master以及多个slave节点,这都是物理的机器,在每一个slave上他都运行着很多的executor,driver程序实际上是跑在一个executor之上的,这个driver会直接向executor发送任务

    master是管理整个集群的节点,master不参与整个任务的分配,他管理的是这些driver的启动,driver到task的启动是由driver来控制的,不是由master来控制的

    在这个架构里,master是一个单点的,为了防止单点,他是通过zookeeper来进行协作的,还有一个备份的master,一旦主master挂掉,所有的slaver会将汇报转发给备份master,master之间的切换是通过zookeeper来进行的

    程序运行模式:YARN分布式模式(yarn-client)

    这里,他是有一个客户端把程序提交到resourcesManager申请资源,然后由resourcesManager去选择一个空闲的nodeManager,去运行一个applicationmaster程序,applicationmaster会为nodemanagers去向resourcesManager申请资源,得到nodemanagers各个executor,他让各个executor启动后去将自己注册到客户端的driver程序上,然后driver在运行过程中,会将任务发送给各个executor,executor里面的task是driver的task

    下面这个图更清晰一些:

    yarn-client这种模式的应用场景解释:

    这种模式启动后,会把所有信息都发送到driver端,driver端一旦退出,整个应用程序会全部销毁,所以在跑长期的应用,比如要跑十几个小时,你把电脑关上,那就失败,那就不要用yarn-client了

    程序运行模式:YARN分布式模式(yarn-cluster)

    yarn-cluster和yarn-client比较类似,但是driver不在运行在client端,driver运行在applicationmaster之上,除了这里不一样,其他都一样

    即,yarn-cluster下,client端,他的作用只是把你的任务提交到集群里面,然后由集群选择一个节点去运行,此时你的客户端程序完全退出对集群没有任何关系,集群是会继续跑你的程序

    对比之下,yarn-client存在的原因还有:

    在yarn-cluster里面你的applicationmaster是跑在任意一个nodemanager的,这个节点上,你是没法控制它的,比如我想控制程序的执行,再输入一个参数什么的,是很难做到这样的

    再比如

    yarn-client这种模式,我可以在client端做各种各样的事情,比如进行一些初始化,加载一些东西,或者像python需要一些必要的环境,这个时候,就需要在client端把事情都做好,依赖的软件都装好,由client去运行程序就行了,而如果是cluster这种,把程序提交到任意一个节点,万一那个节点缺少一些环境,那就没法运行

    其他

    当Spark读取如hdfs的文件作为输入时,会根据具体数据格式对应的InputFormat进行解析,一般是将若干个Block合并成一个输入分片,称为InputSplit,注意InputSplit不能跨越文件。
    随后将为这些输入分片生成具体的Task。InputSplit与Task是一一对应的关系。
    随后这些具体的Task每个都会被分配到集群上的某个节点的某个Executor去执行。
    • 每个节点可以起一个或多个Executor。
    • 每个Executor由若干core组成,每个Executor的每个core一次只能执行一个Task。
    • 每个Task执行的结果就是生成了目标RDD的一个partiton

    注意: 这里的core是虚拟的core而不是机器的物理CPU核,可以理解为就是Executor的一个工作线程。

    而 Task被执行的并发度 = Executor数目 * 每个Executor核数。

    最后

    sparkjobserver很多大公司都在用

  • 相关阅读:
    ubuntu
    ubuntu
    ubuntu14.04,安装Gnome 15.10 (桌面)
    ubuntu14.04,安装Gnome 15.10 (桌面)
    Ubuntu 14.04.3 LTS如何安装谷歌输入法
    Ubuntu 14.04.3 LTS如何安装谷歌输入法
    ubuntu 安装 删除 卸载 Deb 包文件
    失去爆破音规律
    单词发音规律
    英式音标和美式音标的差异
  • 原文地址:https://www.cnblogs.com/sorco/p/7066211.html
Copyright © 2020-2023  润新知