本博文内容主要包括:
1、SparkStreaming 中的Transformations
2、SparkStreaming 中的状态管理
一:SparkStreaming中的Transformation:
1、DStream就是一个RDD之上的一个抽象,DStream和时间结合起来就不断的触发产生RDD的实例,可以说我们对Dstream的操作就初步定义了对RDD的操作,只不过需要时间的间隔也就是internalbatch去激活这个模板,生成具体的RDD的实例和具体的job.
2、我们鼓励Repartition,更多的是把更多的partition变成更少的partition,进行流的碎片的整理,我们不太鼓励把更少的partition变成更多的partion,因为会牵扯shuffle。
3、DStream是离散流,离散流就没状态,除了计算每个时间间隔产生一个job,我们还有必要计算过去十分钟或者半个小时,所以这个时候我们需要维护这个状态。后台spark提供了专门维护这个状态的函数updateStateByKey(func),即基于key,我们可以进行多个状态的维护。因为你可以把每一个时间间隔都做为一个状态,例如每一秒钟做为一个状态,我算下过去十分钟或者半个小时。值的更新就是通过传进来的func函数。
4、Transform:
截图来自:
http://spark.apache.org/docs/latest/streaming-programming-guide.html
编程的逻辑是作用于RDD
Transform操作,允许任意的RDD和RDD的操作被应用在DStream上。他可以使这些RDD不容易暴露在DstreamAPI中。比如让两个batch产生join操作而不暴露在DstreamAPi中,然后你可以很容易的使用transform来做这。这将是非常有作用的,例如,能够将实时数据清理通过将输入的数据流和预先计算的垃圾信息过滤掉。
5、UpdateByKey
UpdaeStateByKey的操作,允许你维护任意的不断通过新的信息来更新的状态。使用这个函数你必须遵守两个步骤
1).定义一个状态:这个状态可以是任意的数据类型
2).定义一个状态更新函数:怎么样去使用从一个数据流中产生的旧的状态和新的状态来更新出一个状态。
6、forecachRDD(func)
mapWithState将流式的状态管理性能提高10倍以上foreachRDD(func)中的函数func是作用于最后一个RDD,也就是结果RDD,如果RDD没有数据,就不需要进行操作,foreachRDD()可以将数据写在Redis/Hbase/数据库/具体文件中,foreachRDD是在Driver程序中执行的,func就是action。
7、updateStateByKey
1) 在这里我们深入updateDateByKey的源码分析,首先进入PairDStreamFunctions.scala
2)我么可以看到创建了MapWithStateDStreamImpl:
3)我们可以看到updateStateByKey为实验性API
4)接下来我们进入StateDStream
5)在StateDStream我们可以看到利用computerPreviousRDD
6)我们进入computerPreviousRDD,可以发现此时的性能瓶颈。
cogroup是updateStateByKey性能的瓶颈,所有的老数据,过去的数据都要进行cogroup操作,即使新的数据pairedRDD只有一条记录,也要把所有的老记录都要进行cogroup操作。这时相当耗时的。理论上讲,只应对这条记录对应的key和历史的一批数据中对应的这个key进行更新操作就行了,而它更新全部的,99%的时间都是浪费和消耗。性能非常低。也会产生shuffle。而下面的MapWithState则只更新你必须要更新的,所以极大提升了性能。
MapWithState只需要更新你必须更新的,没有必要更新所有的记录,官方宣传这个api会把流式的状态管理性能提升10倍以上。
我们可以看到关于MapWithState官方的注释写的非常的清楚
/**
* :: Experimental ::
* Return a [[MapWithStateDStream]] by applying a function to every key-value element of
* `this` stream, while maintaining some state data for each unique key. The mapping function
* and other specification (e.g. partitioners, timeouts, initial state data, etc.) of this
* transformation can be specified using [[StateSpec]] class. The state data is accessible in
* as a parameter of type [[State]] in the mapping function.
*
* Example of using `mapWithState`:
* {{{
* // A mapping function that maintains an integer state and return a String
* def mappingFunction(key: String, value: Option[Int], state: State[Int]): Option[String] = {
* // Use state.exists(), state.get(), state.update() and state.remove()
* // to manage state, and return the necessary string
* }
*
* val spec = StateSpec.function(mappingFunction).numPartitions(10)
*
* val mapWithStateDStream = keyValueDStream.mapWithState[StateType, MappedType](spec)
* }}}
*
* @param spec Specification of this transformation
* @tparam StateType Class type of the state data
* @tparam MappedType Class type of the mapped data
*/
@Experimental
def mapWithState[StateType: ClassTag, MappedType: ClassTag](
spec: StateSpec[K, V, StateType, MappedType]
): MapWithStateDStream[K, V, StateType, MappedType] = {
new MapWithStateDStreamImpl[K, V, StateType, MappedType](
self,
spec.asInstanceOf[StateSpecImpl[K, V, StateType, MappedType]]
)
}
补充说明:
使用Spark Streaming可以处理各种数据来源类型,如:数据库、HDFS,服务器log日志、网络流,其强大超越了你想象不到的场景,只是很多时候大家不会用,其真正原因是对Spark、spark streaming本身不了解。
博文内容源自DT大数据梦工厂Spark课程。相关课程内容视频可以参考:
百度网盘链接:http://pan.baidu.com/s/1slvODe1(如果链接失效或需要后续的更多资源,请联系QQ460507491或者微信号:DT1219477246 获取上述资料)。