![1a6921fd95e03783132f169a0f581668.png](https://i-blog.csdnimg.cn/blog_migrate/950bbfc7e2411b5c941809ba7a179bde.jpeg)
目录
天小天:(一)Spark Streaming 算子梳理 — 简单介绍streaming运行逻辑
天小天:(二)Spark Streaming 算子梳理 — flatMap和mapPartitions
天小天:(三)Spark Streaming 算子梳理 — transform算子
天小天:(四)Spark Streaming 算子梳理 — Kafka createDirectStream
天小天:(五)Spark Streaming 算子梳理 — foreachRDD
天小天:(六)Spark Streaming 算子梳理 — glom算子
天小天:(七)Spark Streaming 算子梳理 — repartition算子
天小天:(八)Spark Streaming 算子梳理 — window算子
前言
本章主要讲解glom
算子的实现原理。
看例子
首先还是看一个简单地例子。
package streaming
import org.apache.spark.{SparkConf, rdd}
import org.apache.spark.rdd.RDD
import org.apache.spark.streaming.{Seconds, StreamingContext}
import scala.collection.mutable
/**
* @date 2019/01/21
*/
object Api {
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setAppName("api").setMaster("local[2]")
val rddQueue = new mutable.Queue[RDD[Int]]()
val ssc = new StreamingContext(sparkConf, Seconds(2))
// consume from rddQueue
val lines = ssc.queueStream(rddQueue)
// glom
lines.glom().map(x => for(i <- x) println("glom ==> " + i)).print()
ssc.start()
// produce to rddQueue
for (i <- 1 to 30) {
rddQueue.synchronized {
rddQueue += ssc.sparkContext.makeRDD(1 to 1000, 10)
}
Thread.sleep(1000)
}
ssc.stop()
}
}
这段代码map
执行的结果为:
glom ==> 1
glom ==> 2
glom ==> 3
glom ==> 4
glom ==> 5
glom ==> 6
glom ==> 7
glom ==> 8
glom ==> 9
glom ==> 10
glom ==> 11
glom ==> 12
glom ==> 13
glom ==> 14
glom ==> 15
glom ==> 16
....
glom
的作用是:把某个批次的一个分区的元素从迭代器类型转换为Array
类型。
源码分析
DStream分析
先看下DStream中的源码
/**
* Return a new DStream in which each RDD is generated by applying glom() to each RDD of
* this DStream. Applying glom() to an RDD coalesces all elements within each partition into
* an array.
*/
def glom(): DStream[Array[T]] = ssc.withScope {
new GlommedDStream(this)
}
很简单,就是实例化了GlommedDStream
类。
GlommedDStream分析
package org.apache.spark.streaming.dstream
import scala.reflect.ClassTag
import org.apache.spark.rdd.RDD
import org.apache.spark.streaming.{Duration, Time}
private[streaming]
class GlommedDStream[T: ClassTag](parent: DStream[T])
extends DStream[Array[T]](parent.ssc) {
override def dependencies: List[DStream[_]] = List(parent)
override def slideDuration: Duration = parent.slideDuration
override def compute(validTime: Time): Option[RDD[Array[T]]] = {
parent.getOrCompute(validTime).map(_.glom())
}
}
我们只看compute
方法的实现,就是执行RDD
的glom
方法。
RDD
分析
/**
* Return an RDD created by coalescing all elements within each partition into an array.
*/
def glom(): RDD[Array[T]] = withScope {
new MapPartitionsRDD[Array[T], T](this, (context, pid, iter) => Iterator(iter.toArray))
}
上面是RDD
中glom
方法实现。主要的是实例化MapPartitionsRDD
。MapPartitionsRDD
类的在(二)Spark Streaming 算子梳理 — flatMap和mapPartitions已经介绍过来,这里就不在说了。
我们主要看下方法的第二个入参:(context, pid, iter) => Iterator(iter.toArray)
。这段代码的作用是把每个partition的元素从Iterator
类型转换为Array
类型之后再包装到迭代器中返回。这段代码也是glom
方法最核心的代码。
注意
其实到上面已经讲完了glom
的方法,其中有一点需要注意的是,由于glom
会把每个批次每个分区的数据从Iterator
类型转换为Array
类型,所以如果每个分区的数据非常大的话会出现OOM的情况。
源码地址
源码地址