Spark整理

Spark介绍

 

  1. 一个分布式的并行计算框架
  2. spark是下一代的map-reduce,扩展了mr的数据处理流程
  3. executor都是装载在container里运行,container默认内存是1G(参数yarn.scheduler.minimum-allocation-mb定义)
  4. AM(Application Master)在Spark中叫driver,AM向RM申请的是executor资源,当分配完资源后,executor启动后,由spark的AM向
  5. executor分配task,分配多少task、分配到哪个executor由AM决定,可理解为spark也有个调度过程,这些task都运行在executor的坑里
  6. Executor有线程池多线程管理这些坑内的task

Executor伴随整个app的生命周期(申请的进程的内存一直到任务结束)
线程池模型,省去进程频繁启停的开销

MapReduce的问题


调度慢,启动map、reduce太耗时
计算慢,每一步都要保存中间结果落磁盘
API抽象简单,只有map和reduce两个原语(需要通过脚本把map和reduce串起来)
缺乏作业流描述,一项任务需要多轮mr

具体描述:
MR中 : 启动map进程,启动reduce进程,所以启动慢 
spark:先启动executor进程,再启动线程:比如10个线程:8 map task(线程)2 reduce(线程)

MR:map->reduce的中间结果在磁盘
spark:map->reduce的中间结果也在磁盘(默认)
除非,进行cache(它调用的是persist)默认在内存中

spark只需要通过代码就能把很多的数据处理串在一起:
df = spark.map.reduce
df1 = df.groupBy().count()
通过spark shell的方式查看具体的数据

Spark解决的问题


– 最大化利用内存cache(内存计算下,Spark比MR快100倍)
– 中间结果放内存,加速迭代
  input --> iter1 --> 分布式内存 --> iter2 分布式内存
– 某结果集放内存,加速后续查询和处理,解决运行慢的问题
  input --> 分布式内存 --> query1,query2,...
- 丰富的API(解决API单一问题)
  包括Transformations和Action
  Transfomation变换的api,比如map可对每一行做变换,filter过滤出符合条件的行等,这些API实现用户算法,灵活。
  spark提供很多转换和动作,很多基本操作如Join,GroupBy已经在RDD转换和动作中实现。不需用户自己实现。

  写操作就是action:写磁盘,写内存
  cache属于transformation,df.cache告诉任务df需要执行之后放到内存中
- 完整作业描述,将用户的整个作业穿起来。关键是这3行。可以立即解释。不像mr那样,需要实现多个map和reduce脚本,解决MR缺乏作业流描述问题
  val file = sc.textFile(hdfs://input)
  val counts = file.flatMap(
  line => line.split(" "))
              .map(word => (word, 1))
              .reduceByKey(_ + _)
  counts.saveAsTextFile(hdfs://output)

Spark核心


• Spark基于弹性分布式数据集(RDD)模型。
• RDD( Resilient Distributed Dataset ):弹性分布式数据集(相当于集合),它的本质是数据
  集的描述(只读的、可分区的分布式数据集),而不是数据集本身
• RDD的关键特征:
   RDD使用户能够显式将计算结果保存在内存中,控制数据的划分
   使用更丰富的操作来处理,只读(由一个RDD变换得到另一个RDD,但是不能对本身的RDD修改)
   记录数据的变换而不是数据本身保证容错(lineage)

• RDD采用数据应用变换(map,filter,join),若部分数据丢失,RDD拥有足够的信息得知这部分数据是如何计算得到的,
  可通过重新计算来得到丢失的数据
  容错:1.备份数据 2.记录更新方式
   变换方式:rdd1->rdd2->rdd3
   可以知道:rdd2 = rdd1->rdd2
• 恢复数据方法很快,无需大量数据复制操作,可以认为Spark是基于RDD模型的系统
– 懒操作,延迟计算,action的时候才操作
– 瞬时性,用时才产生,用完就释放

RDD来源:


– 读取数据,如从HDFS中读数据构建RDD(Sparkcontext (sc)是spark的入口,编写spark程序用到
  的第一个类,包含sparkconf sparkenv等类)
– 通过别的RDD转换过来
   val b = a.map(x => (x, 1))
– 定义一个scala数组
   val c = sc.parallelize(1 to 10, 1)
– 有一个已经存在的RDD通过持久化操作生成
  val d = a.persist(), a.saveAsHadoopFile(“/xxx/xxx/”)
- Dataframe转换过来,这样就可以从hive过来数据

 

Spark针对RDD提供的操作:transformations和action

  •  transformations(如上文)是RDD之间的变换,action会对数据执行一定的操作
  •  transformations采用懒策略,仅在对相关RDD进行action提交时才触发计算

RDD分区和依赖:
• 每个RDD包含了数据分块/分区(partition)的集合,每个partition是不可分割的
– 实际数据块的描述(实际数据到底存在哪,或者不存在)
– 其值依赖于哪些partition

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

 宽依赖: B的每个partition依赖于A的所有partition(需要用到之前所有的数据)
    如groupByKey、reduceByKey、join……,由A产生B时会先对A做shuffle分桶
 窄依赖: B的每个partition依赖于A的常数个partition(需要用到之前部分的数据)
    如map、filter、union等     (图片来自网络)

• 从后往前,将宽依赖的边删掉,连通分量及其在原图中所有依赖的RDD,构成一个stage
• DAG是在计算过程中不断扩展 ,在action后才会 启动计算
• 每个stage内部尽可能多地包含一组具有窄依赖关系的转换,并将它们流水线并行化(pipeline)

• 从后往前,将宽依赖的边删掉,连通分量及其在原图中所有依赖的RDD,构成一个stage
• DAG是在计算过程中不断扩展 ,在action后才会 启动计算
• 每个stage内部尽可能多地包含一组具有窄依赖关系的转换,并将它们流水线并行化(pipeline)
• 每个partition的计算就是一个task,task是调度的基本单位
• 一个stage会等待它包含的其他stage中的任务全部完成才加入调度
• 遵循数据局部性原则,使得数据传输代价最小
 
1. 如果一个任务需要的数据在某个节点的内存中,这个任务就会被分配至那个节点
  2. 需要的数据在某个节点的文件系统中,就分配至那个节点
     (此时的调度指的是:由spark的AM来决定计算partition的task,分配到哪个executor上)
• 如果此task失败,AM会重新分配task
• 如果task依赖的上层partition数据已经失效了,会先将其依赖的partition计算任务再重算一遍
• 宽依赖中被依赖partition,可以将数据保存HDFS,以便快速重构(checkpoint)
 
注: 窄依赖只依赖上层一个partition,恢复代价较少;宽依赖依赖上层所有partition,如果数据丢
       失,上层所有partiton都要重算
• 可以指定保存一个RDD的数据至节点的cache中,如果内存不够,会LRU释放一部
  分,仍有重构的可能

 

Spark优化相关

内存管理


• Executor的内存分为3块
    第一块:让task执行代码,默认占executor总内存的20%
    第二块:task通过shuffle过程拉取上一个stage的task的输出后,进行聚合等操作时使用,默认也占20%
    第三块:让RDD持久化时使用,默认占60%
• Task的执行速度和每个executor进程的CPU Core数量有直接关系,一个CPU Core同一
    时间只能执行一个线程,每个executor进程上分配到的多个task,都是以task一条线程的
    方式,多线程并发运行的。如果CPU Core数量比较充足,而且分配到的task数量比较合
    理,那么可以比较快速和高效地执行完这些task线程

重要的参数


• num-executors:该作业总共需要多少executor进程执行(建议50~100个左右合适)
• executor-memory:单个excutor的能使用的内存的大小,executor-memory *num-executors
  就是本次任务需要的内存(尽量不要超过最大总内存的1/3~1/2 4G~8G较合适)
• executor-cores:单个executor 执行给的core的数量,不能超过单节点的core的总和;
  单个core同一时间只能执行一个task,在不影响其他人作业,且不超过节点的core的上限的时候,这个值越大执行的效率越高;该参数决定每个
  executor进程并行执行task线程的能力(不要超过总CPU Core的1/3~1/2 2~4个较合适) 

 

开发原则


1、避免创建重复的RDD
2、尽可能复用同一个RDD  
3、对多次使用的RDD进行持久化处理
   借助cache()和persist()方法
4、避免使用shuffle类算子
  在spark作业运行过程中,最消耗性能的地方就是shuffle过程
  将分布在集群中多个节点上的同一个key,拉取到同一个节点上,进行聚合和join处理,比如
  groupByKey、reduceByKey、join等算子,都会触发shuffle,map为非shuffle算子

5、使用map-side预聚合的shuffle操作
6、使用Kryo优化序列化性能(不使用默认的Java序列化机制)

 

Spark技术栈


• Spark和Hadoop关系: Spark依赖于HDFS文件系统,如果是Spark on YARN部署模式,又依赖于YARN计算框架
• Spark Core:基于RDD提供操作接口,利用DAG进行统一的任务规划
• Spark SQL:Hive的表 + Spark的里。通过把Hive的HQL转化为Spark DAG计算来实现
• Spark Streaming:Spark的流式计算框架
• MLIB:Spark的机器学习库,包含常用的机器学习算法
• GraphX:Spark图并行操作库

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值