Spark编程模型

25 篇文章 0 订阅
常见术语
ApplicationSpark的应用程序,包含一个Driver program和若干个Executor
SparkContext
  • Spark应用程序的入口,负责调度各个运算资源,协调各个Worker Node上的Executor。
  • RDD的初始创建都是有SparkContext来负责的,将内存中的集合或者外部文件系统作为输入源。
  • 在SparkContext的初始化过程中,Spark会分别创建DAGScheduler作业调度和TaskScheduler任务调度两级调度模块。
  • SparkContext运行在Driver上
Driver program运行Application的main()函数并且创建SparkContext
Executor是Application运行在一个Worker Node上的一个进程,该进程负责运行task,并且负责将数据存在内存或者磁盘上。
每个Application都会申请各自的Executors来处理任务
Cluster Manager在集群上获取资源的外部服务(例如:Standalone、Mesos、Yarn)
Work Node集群中任何可以运行Application代码的节点,运行一个或多个Executor进程
Task运行在Executor上的工作单元。每个Task最多只能处理一个128MB的Block,也就是说如果Block的大小大于128MB,那么就会启动多个Task来处理对应的Block
JobSparkContext提交具体的Action操作,常和Action对应。
Stage
  • 每个Job会被拆分很多组任务(task),每组任务被称为Stage,也称TaskSet。
  • 调度阶段(Stage)的划分是以ShuffleDependency作为依据的,也就是说当某个RDD运算需要将数据进行shuffle操作时,这个包含了Shuffle依赖关系的RDD将被用来作为输入信息,构建一个新的调度阶段,以此为依据划分调度阶段,可以确保有依赖关系的数据能够按照正确的顺序得到处理和运算。
RDDResilient distributed datasets 的简称,中文为弹性分布式数据集,是Spark最核心的类和模块。(就是一个类)。
一个RDD的生成只有两种途径,一是来自于内存集合和外部存储系统,另一种是通过转换操作来自于其他RDD,比如map、filter、join,等等。
DAGScheduler
  • 根据Job构建基于Stage的DAG,并提交Stage(TaskSet)给TaskScheduler。
  • DAGScheduler在SparkContext初始化的过程中被实例化。一个SparkContext对应创建一个DAGScheduler。
  • RDD的Action操作,也就是提交作业(Job)的时候会调用DAGScheduler的作业提交接口。
  • DAGScheduler和具体的部署运行模式无关。
  • DAGScheduler运行在Driver上
TaskScheduler
  • 将Taskset提交给Worker Node集群中具体的Executor运行并返回结果
  • TaskScheduler在不同的运行模式下是不同的的。
Transformation/ActionSpark API的两种类型
Transformation返回值还是一个RDD
Action返回值不是一个RDD,而是一个Scala集合
所有的Transformation都是采用懒策略,如果将Transformation提交是不会执行计算的,计算只有在Action被提交时才触发。

Spark支持的RDD Transformation和Action
Transformationmap(f:T=>U) : RDD[T]=>RDD[U]
filter(f:T=>Bool) : RDD[T]=>RDD[T]
flatMap(f:T=>Seq[U]) : RDD[T]=>RDD[U]
sample(fraction:Float) : RDD[T]=>RDD[T] (Deterministic sampling)
groupByKey() : RDD[(K,V)]=>RDD[(K,Seq(V))]
reduceByKey(f:(V,V)=>V) : RDD[(K,V)]=>RDD[(K,V)]
union() : (RDD[T],RDD[T])=>RDD[T]
join() : (RDD[(K,V)],RDD[(K,W)])=>RDD[(K,(V,W))]
cogroup() : (RDD[(K,V)],RDD[(K,W)])=>RDD[(K,(Seq(V),Seq(W)))]
crossProduct() : (RDD[T],RDD[U])=>RDD[(T,U)]
mapValues(f:V=>W) : RDD[(K,V)]=>RDD[(K,W)] (Preserves partitioning)
sort(c:Comparator[K]) : RDD[(K,V)]=>RDD[(K,V)]
partitionBy(p:Patitioner[K]) : RDD[(K,V)]=>RDD[(K,V)]
Actioncount() : RDD[T]=>Long
collect() : RDD[T]=>Seq[T]
reduct(f:(T,T)=>T) : RDD[T]=>T
lookup(k:K) : RDD[(K,V)]=>Seq[V] (On hash/range partitioned RDDs)
save(pash:String) : Outputs RDD to a stoage system,e.g. HDFS

Spark RDD 接口
partitions分区,一个RDD会有一个或者多个分区,这个属性描述的是RDD的分区信息每一个RDD分区计算操作都在一个单独的任务中被执行.
示例代码:
scala> val rdd = sc.parallelize(1 to 100,2)
rdd: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:21

scala> rdd.partitions.size
res0: Int = 2
preferredLocations(p)对于分区p而言,返回数据本地化计算的节点,以从Hadoop中读取数据生成RDD为例,preferredLocations返回每一个数据块所在的机器名或者IP地址,如果每一块数据有多份存储的,那么就返回多个机器地址.
示例代码:
scala> val rdd = sc.textFile("hdfs://192.168.1.120:9000/epg/2015-12-07")
15/12/08 16:17:25 INFO MemoryStore: ensureFreeSpace(165720) called with curMem=87627, maxMem=2223023063
15/12/08 16:17:25 INFO MemoryStore: Block broadcast_1 stored as values in memory (estimated size 161.8 KB, free 2.1 GB)
15/12/08 16:17:25 INFO MemoryStore: ensureFreeSpace(15523) called with curMem=253347, maxMem=2223023063
15/12/08 16:17:25 INFO MemoryStore: Block broadcast_1_piece0 stored as bytes in memory (estimated size 15.2 KB, free 2.1 GB)
15/12/08 16:17:25 INFO BlockManagerInfo: Added broadcast_1_piece0 in memory on localhost:44503 (size: 15.2 KB, free: 2.1 GB)
15/12/08 16:17:25 INFO SparkContext: Created broadcast 1 from textFile at <console>:21
rdd: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[4] at textFile at <console>:21

scala> val hadoopRDD = rdd.dependencies(0).rdd
hadoopRDD: org.apache.spark.rdd.RDD[_] = hdfs://192.168.1.120:9000/epg/2015-12-07 HadoopRDD[3] at textFile at <console>:21

scala> hadoopRDD.partitions.size
15/12/08 16:17:46 INFO FileInputFormat: Total input paths to process : 70
res2: Int = 70

scala> hadoopRDD.preferredLocations(hadoopRDD.partitions(0))
res3: Seq[String] = WrappedArray(slave05, slave10)
dependencies()RDD的依赖关系
compute(p,context)对于分区p而言,进行迭代计算,返回一个分区的最终迭代器.在rdd实例化开始计算的时候就是调用这个函数
partitioner()partitioner就是RDD的分区函数,目前在Spark中实现了两种类型的分区函数,即HashPartitioner(哈希分区)和RangePatitioner(区域分区),且partitioner这个属性值只存在于(K,V)类型的RDD中,对于非(K,V)类型的partitioner的值就是None.partitioner函数既决定了RDD本身的分区数量,也可作为其父RDD Shuffle输出(MapOutput)中每个分区进行数据切割的一句.
示例代码:
scala> val rdd = sc.makeRDD(1 to 10,2).map(x=>(x,x))
rdd: org.apache.spark.rdd.RDD[(Int, Int)] = MapPartitionsRDD[9] at map at <console>:21

scala> rdd.partitioner
res4: Option[org.apache.spark.Partitioner] = None

scala> val group_rdd = rdd.groupByKey(new org.apache.spark.HashPartitioner(3))
group_rdd: org.apache.spark.rdd.RDD[(Int, Iterable[Int])] = ShuffledRDD[10] at groupByKey at <console>:23

scala> group_rdd.partitioner
res5: Option[org.apache.spark.Partitioner] = Some(org.apache.spark.HashPartitioner@3)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值