分布式计算框架Spark

一、Spark三种模式
  1. 本地模式
./bin/run-example SparkPi 10 --master local[2]
  1. 集群模式 Spark Standalone(Spark独立集群模式)
./bin/spark-submit \
	--class org.apache.spark.examples.SparkPi \
	--master spark://master:7077 \
	examples/jars/spark-examples_2.11-2.0.2.jar 100
  1. 集群模式Spark on yarn(yarn-cluster和yarn-client
    spark运行在yarn集群上,可以与其他计算框架共享资源
./bin/spark-submit \
	--class org.apache.spark.examples.SparkPi \
	--master yarn-cluster \
	examples/jars/spark-examples_2.11-2.0.2.jar 100  
yarn-cluster和yarn-client本质区别:AM进程
二、集群模式Spark on yarn
2.1 yarn-cluster模式

driver在AM中,AM(driver)负责向yarn申请资源、作业的调度与监控。一旦用户提交完作业后,client可以关闭,作业在yarn集群上运行,数据结果会生成在AM的日志中,适用于生产环境。

  1. spark-submit脚本提交,向yarn(RM)中提交ApplicationMaster程序、AM启动的命令和需要在Executor中运行的程序等
  2. RM收到请求之后,选择一个NM,在其上开启一个container,在container中开启AM,并在AM中完成SC的初始化
  3. AM向RM注册并请求资源,这样用户可以在RM中查看任务的运行情况。RM根据请求采用轮询的方式和RPC协议向各个NM申请资源并监控任务的运行状况直到结束
  4. AM申请到资源之后,与对应的NM进行通信,要求在其上获取到的Container中开启executor,开启之后,向AM中的SC注册并申请task
  5. AM中的SC分配task给executor,executor运行task并向AM中的SC汇报自己的状态和进度
  6. 应用程序完成之后(各个task都完成之后),AM向RM申请注销并关闭自己

ApplicationMaster的作用:

  1. 当前的Application申请资源
  2. 给nodemanager发送消息 启动Executor。
  3. 任务调度
2.2 yarn-client模式

driver在客户端节点上,作业提交后,启动driver进程,AM仅向RM请求executor资源并通知指定的NM启动executor,driver会和对应的executor进行通信来调度任务,client不能离开,适用交互与调试 。

  1. spark-submit脚本提交,driver进程在客户端本地运行
  2. Client向RM申请启动AM,同时在SparkContext(client上)中创建DAGScheduler和TaskScheduler
  3. RM收到请求之后,根据资源分布选择其中一个NM,分配container,并在container中开启AM
  4. client中的SC初始化完成之后,与AM进行通信,向RM注册,根据任务信息向RM申请资源
  5. AM申请到资源之后,与NM进行通信,要求在它申请的container中开启executor。Executor在启动之后会向SC注册并申请task
  6. SC分配task给executor,executor执行任务并向Driver汇报,以便客户端可以随时监控任务的运行状态
  7. 任务运行完成之后,client的SC向RM注销自己并关闭自己

ApplicationMaster的作用:

  1. 为当前的Application申请资源
  2. 给NodeManager发送消息启动Executor

ApplicationMaster有launch Executor和申请资源的功能,并没有作业调度的功能。

Spark standalone
  • master/slave结构
    • Master:类似yarn中的RM
    • Worker:类似yarn中的NM
三、MapReduce和Spark作业的区别
  1. MapReduce (Hive)的一个map task/reduce task是进程;Spark的一个map task/reduce task是线程
  2. container(进程需要的资源CPU,内存,IO)是进程。在mapreduce中container作为一个map task或者一个reduce task;在spark container可以同时拥有map task(线程)+ reduce task(线程)
  3. MapReduce分布式计算框架,解决数据分布式计算问题。spark在MR基础上做分布式多线程,若不使用cache/persist,spark默认会遵循MR执行过程,过程会有shuffle和落地到磁盘。cache()调用persist(memory only),数据缓存到内存,persist()会落地磁盘、内存、序列化等等。
  4. 一个MR任务就是一个job,一个job分为多个task,task又可以分为map task和reduce task,每个task在自己的进程中运行。在任务执行过程中,运行完的task进程可以释放进程资源。复杂的hadoop任务由多个MR job串行组成;一个spark任务是一个application,一个app可分为多个job(由action算子划分),一个job分为多个stage(由shuffle划分),一个stage中包含多个task(map task 或者 reduce task:线程)。一个job可以有一个进程或者多个进程。进程生命周期和application一样,只有当一个app任务完成时,进程所占用的所有资源才会被释放。一个app任务由多个job并行或者串行运行。
四、Spark的application
  • spark中的job和MR中的job意义不一样,spark job是指一个application中的action算子触发一个job,MR job是一个MR任务。
  • 一个Application通过SparkContext来解析,每个app可有一个或多个job,并行或串行运行job
  • spark中一个action算子触发一个job
  • 一个job包含多个stage,stage是以shuffle过程来划分,每个stage包含多个task
  • 与MR不同,spark的task(线程)可运行在一个进程中,进程的生命周期和app周期相同,任务完成后资源全部释放

优点:加快spark运行速度(MR任务过程中数据需要落地到磁盘,spark任务中间数据可cache到内存中,加快运算速度),task可快速启动(MR task是进程,启动较慢,spark task是线程,启动快)
缺点:每个application有固定数目的executor和内存(自定义或者默认)

细化内部结构
  • application:一个driver和多个job构成
  • job:由多个stage组成
  • stage:对应一个taskset
  • taskset:对应一组关联的相互之间没有shuffle依赖关系的task组成
  • task:任务最小的工作单元
Driver Program(spark application入口)
  • driver是Spark的核心组件
  • 构建SparkContext(spark应用的入口,创建需要的变量,包含集群的配置信息)
  • 将一个application任务依据action算子划分多个job,每个job转换为DAG图,根据shuffle将每个DAG图划分为多个stage,根据分区从而生成一系列tasks,再根据tasks向RM申请资源
  • 提交任务并检测任务状态
MR存在的问题
  • 调度慢:启动map、reduce进程太耗时
  • 计算慢:每一步都要保存中间结果到磁盘
  • API抽象简单:只有map和reduce
  • 缺乏作业流描述:一项复杂任务需要多轮mr
Spark
  • spark是下一代的mapreduce,扩展了mr的数据处理流程的分布式并行计算框架
  • executor装载在container里运行,container默认内存是1G
  • executor分配的内存是executor-memory,向yarn申请的内存是(num-executors+1)* executor-memory
  • AM在spark被称为driver,AM向RM申请executor资源,当分配完资源后,executor启动后,由spark的AM向executor分配task,分配多少task,分配到哪个executor由AM决定
  • executor由线程池多线程管理这些task
spark解决的问题
  • 最大化利用内存cache
  • 中间结果放入内存,加速迭代
  • 加速后续查询和处理,解决运行慢的问题
  • 更加丰富的API(transformation算子和action算子)
  • 完整作业流描述:对整个作业串起来
五、Spark核心-RDD

Spark基于弹性分布式数据集RDD模型,具有良好的通用性、容错性与并行处理数据的能力。
RDD(Resilient Distributed Dataset)弹性分布式数据集,本质是数据集的操作描述(只读、可分区),而不是数据集本身

RDD的特性
  • RDD将数据集的操作保存在内存中,控制数据的划分,提供丰富的API操作
  • RDD本身只读,不可修改(一个RDD转换为另一个RDD)
  • 每一个RDD记录了数据的操作符而不是数据本身来保证容错:若部分数据丢失,可根据RDD记录的操作符来恢复
  • 每个RDD包含了数据分块/分区的集合,每个partition不可分割。每一个partition的计算是一个task,task是调度的基本单位。
  • 懒操作:延时计算,直到action算子才操作
  • 瞬时性:用时才产生,用完就释放

遵循数据局部性原则,使数据传输代价最小

  • 如果一个任务需要的数据在某个节点的内存中,这个task分配到这个节点
  • 需要的数据在某个节点的文件系统中,分配至这个节点(由spark的AM来调度task分配到哪个executor)
RDD提供两类操作:transformations算子和action算子
  • transformations是RDD之间的变换,action会对数据执行一定的操作
  • transformations采用懒操作,仅当action提交才触发计算
RDD之间的依赖关系

宽依赖和窄依赖(rddA=>rddB)

  • 宽依赖:A和B是一对多的关系(shuffle), B的每个partition都依赖于A的每一个partition
    例如:groupByKey、reduceByKey、join……
  • 窄依赖:A和B是一对一关系 ,B的每个partition都依赖于A的常数个partition
问题:如下的DAG图存在可能性吗?

不存在这种情况;原因是DAG图是通过AM下的的driver依据RDD的数据集以及算子操作来解析的,此时没有输入原始数据真正的执行。等到真正执行数据时,数据的流向可能会如上图所示,但是DAG图应该是全连接的shuffle过程。

六、Spark核心-容错
  • 若task失败,AM会重新分配task
  • 窄依赖依赖上一层的partition,恢复代价小;宽依赖依赖上层所有的partition,如果下游数据某个partition丢失,上层partition都要重新计算,导致下游partition的重复计算。
  • 为了使丢失的数据快速恢复,宽依赖的上层RDD cache到内存。
七、Spark调优
7.1 Spark资源参数调优

executor内存分为3种:

  • RDD持久化使用,默认占executor总内存的60%
  • task通过shuffle过程拉取上一个stage的task输出,进行聚合等操作时使用,默认占20%
  • task执行代码使用,默认占20%

task执行速度和每个executor进程的cpu core数量有直接关系,一个cpu同一时间只能执行一个线程,进程中的tasks是以多线程并发运行的,如果cpu core数量充足,那么可以快速高效的执行完这些task线程。

参数:

  • num-executors:作业一共需要多少executor进程执行,建议每个作业运行一般设置5/10/15个左右
  • executor-memory:每个executor进程的内存(申请的总内存量不能超过最大总内存的1/3~1/2),建议4G ~ 8G
  • executor-cores:每个executor进程的CPU core数量,该参数决定executor进程并行执行task线程的能力,建议2~4个
  • driver-memory:driver进程的内存,建议设置多一些(4G),出现collect算子将RDD数据全部拉取到driver上做处理,必须保证该值足够大,否则OOM内存溢出
  • spark.default.parallelism:每个stage的默认task数量
  • spark.storage.memoryFraction:设置RDD持久化数据到executor内存所占的比例,默认0.6
  • spark.shuffle.memeoryFraction:聚合操作占executor内存的比例,默认0.2

spark参数调整可在spark开发中设置conf,或者在提交任务时附加参数配置

7.2 Spark开发调优
  • 原则一:避免创建重复的RDD(对于同一份数据,只需要创建一个RDD,不能重复创建,极大浪费内存)
  • 原则二:尽可能复用相同的RDD(相同的RDD操作可以共用,不同的RDD操作可以并列执行)
  • 原则三:对多次使用的RDD进行持久化处理(cache()/persist())
  • 原则四:避免使用shuffle类算子
    • spark作业运行过程中,最消耗性能的地方就是shuffle过程
    • 将分布在集群中多个节点上的同一个key,拉取到同一节点上,进行聚合或join操作,如groupByKey、reduceByKey、join等,都会触发shuffle
    • Broadcast+map的join操作,不会导致shuffle操作,但前提是RDD数据量较少的情况下(类似于hive中mapjoin)
  • 原则五:使用map-side预聚合的shuffle操作
    • 有shuffle过程且无法用map类算子代替的,尽量使用map-side预聚合算子,类似于MR的combiner
    • 使用reduceByKey或aggregateByKey算子代替groupByKey,因为reduceByKey或aggregateByKey算子会使用用户自定义的函数对每个节点本地相同的key进行预聚合,而groupByKey算子不会预聚合
  • 原则六:使用Kryo优化序列化性能
    • Kryo是一个序列化类库,优化序列化和反序列化性能
    • spark默认使用Java序列化机制进行序列化和反序列化
    • spark支持使用Kryo序列化库,性能比Java序列化库高10倍左右
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值