ref: https://jaceklaskowski.gitbooks.io/spark-structured-streaming/

StruncturedStream的statefule实现基于StateStore,能够记忆历史的结果,从而形成unbounded流式计算。其内部实际上是将历史的统计结果存在StateStore(目前是基于HDFS存储数据)。每次计算时,会执行StateStoreRestore->Agg->StateStoreSave:

stateful机制以来与StateStoreRDD

logical plan逻辑:

StateStoreRestore/Save都是基于StateStoreRDD

StateStoreRDD基于StateStoreCoordinator获取state的location,作为preferred location.

数据来源包含StateStore的历史结果和新batch的RDD数据。

StateStoreRDD is an RDD for executing storeUpdateFunction with StateStore (and data from partitions of a new batch RDD).

最终StateStoreRDD将merge历史的state和新的batch data:

// StateStoreRDD#compute
override def compute(partition: Partition, ctxt: TaskContext): Iterator[U] = {
var store: StateStore = null
val storeId = StateStoreId(checkpointLocation, operatorId, partition.index)
store = StateStore.get(
storeId, keySchema, valueSchema, storeVersion, storeConf, confBroadcast.value.value) // 获取Store
val inputIter = dataRDD.iterator(partition, ctxt) // 新batch的数据
storeUpdateFunction(store, inputIter) // 结合计算,Restore和Save的逻辑不同
}
storeUpdateFunction of StateStoreRestore

Restore时的merge逻辑是将历史state和新batch的数据,按相同的key合并在一起,主要调用store#get(key)

{ case (store, iter) =>
val getKey = GenerateUnsafeProjection.generate(keyExpressions, child.output)
iter.flatMap { row =>
val key = getKey(row)
val savedState = store.get(key)
numOutputRows += 1
row +: savedState.toSeq
}
storeUpdateFunction of StateStoreSave (以outMode=complete为例),主要调用 store#put(key,value)
{ (store, iter) =>
val getKey = GenerateUnsafeProjection.generate(keyExpressions, child.output)
...
outputMode match {
// Update and output all rows in the StateStore.
case Some(Complete) =>
while (iter.hasNext) {
val row = iter.next().asInstanceOf[UnsafeRow]
val key = getKey(row)
store.put(key.copy(), row.copy())
numUpdatedStateRows += 1
}
store.commit()
numTotalStateRows += store.numKeys()
store.iterator().map { case (k, v) =>
numOutputRows += 1
v.asInstanceOf[InternalRow]
}
...

StateStore (HDFSBackedStateStore)

简单理解一下StateStore。直观上,在DStream框架下如果要实现stateful,我们也会把历史的state用一个RDD存下来,每次新的数据计算完成后再跟历史RDD融合(通过checkpoint避免超长lineage)。这个思路是完全正确并且和StructuredStream的思路相似。

  1. key/value的schema
  2. preferred location优化

StateStoreRDD是逻辑上的RDD,因为它的数据实际上来源于history+new batch。

  • 它的partition是new batch的partition。
override protected def getPartitions: Array[Partition] = dataRDD.partitions
  • preferredLocation选择

    p1 -> 计算其对应的历史state store的storeId->从storeCoor获取该storeId的location。(注:可有可无)

    StoreId 由( checkpointLocation, operationId, partition.index)唯一确定。
override def getPreferredLocations(partition: Partition): Seq[String] = {
val storeId = StateStoreId(checkpointLocation, operatorId, partition.index)
storeCoordinator.flatMap(_.getLocation(storeId)).toSeq
}
  • compute过程
override def compute(partition: Partition, ctxt: TaskContext): Iterator[U] = {
var store: StateStore = null
val storeId = StateStoreId(checkpointLocation, operatorId, partition.index)
store = StateStore.get(
storeId, keySchema, valueSchema, storeVersion, storeConf, confBroadcast.value.value)
val inputIter = dataRDD.iterator(partition, ctxt)
storeUpdateFunction(store, inputIter)
}

※ 根据storeId,key/valueSchema, version等信息获取store (StateStore#get)

  def get(
storeId: StateStoreId,
keySchema: StructType,
valueSchema: StructType,
version: Long,
storeConf: StateStoreConf,
hadoopConf: Configuration): StateStore = {
require(version >= 0)
val storeProvider = loadedProviders.synchronized {
startMaintenanceIfNeeded()
val provider = loadedProviders.getOrElseUpdate(
storeId,
new HDFSBackedStateStoreProvider(storeId, keySchema, valueSchema, storeConf, hadoopConf))
reportActiveStoreInstance(storeId)
provider
}
storeProvider.getStore(version)
}

→ storeProvider.getStore(version)

基于type MapType = java.util.concurrent.ConcurrentHashMap[UnsafeRow, UnsafeRow]

loadMap从HDFS中将数据读入到Map中。

  override def getStore(version: Long): StateStore = synchronized {
require(version >= 0, "Version cannot be less than 0")
val newMap = new MapType()
if (version > 0) {
newMap.putAll(loadMap(version))
}
val store = new HDFSBackedStateStore(version, newMap)
logInfo(s"Retrieved version $version of ${HDFSBackedStateStoreProvider.this} for update")
store
}

StructuredStream StateStore机制的更多相关文章

  1. 笔记:Binder通信机制

    TODO: 待修正 Binder简介 Binder是android系统中实现的一种高效的IPC机制,平常接触到的各种XxxManager,以及绑定Service时都在使用它进行跨进程操作. 它的实现基 ...

  2. JAVA回调机制(CallBack)详解

    序言 最近学习java,接触到了回调机制(CallBack).初识时感觉比较混乱,而且在网上搜索到的相关的讲解,要么一言带过,要么说的比较单纯的像是给CallBack做了一个定义.当然了,我在理解了回 ...

  3. 谈谈DOMContentLoaded:Javascript中的domReady引入机制

    一.扯淡部分 回想当年,在摆脱写页面时js全靠从各种DEMO中copy出来然后东拼西凑的幽暗岁月之后,毅然决然地打算放弃这种处处“拿来主义”的不正之风,然后开启通往高大上的“前端攻城狮”的飞升之旅.想 ...

  4. 路由的Resolve机制(需要了解promise)

    angular的resovle机制,实际上是应用了promise,在进入特定的路由之前给我们一个做预处理的机会 1.在进入这个路由之前先懒加载对应的 .js $stateProvider .state ...

  5. Android权限管理之Permission权限机制及使用

    前言: 最近突然喜欢上一句诗:"宠辱不惊,看庭前花开花落:去留无意,望天空云卷云舒." 哈哈~,这个和今天的主题无关,最近只要不学习总觉得生活中少了点什么,所以想着围绕着最近面试过 ...

  6. Java学习之反射机制及应用场景

    前言: 最近公司正在进行业务组件化进程,其中的路由实现用到了Java的反射机制,既然用到了就想着好好学习总结一下,其实无论是之前的EventBus 2.x版本还是Retrofit.早期的View注解框 ...

  7. .NET Core采用的全新配置系统[10]: 配置的同步机制是如何实现的?

    配置的同步涉及到两个方面:第一,对原始的配置文件实施监控并在其发生变化之后从新加载配置:第二,配置重新加载之后及时通知应用程序进而使后者能够使用最新的配置.要了解配置同步机制的实现原理,先得从认识一个 ...

  8. Go结构体实现类似成员函数机制

    Go语言结构体成员能否是函数,从而实现类似类的成员函数的机制呢?答案是肯定的. package main import "fmt" type stru struct { testf ...

  9. 操作系统篇-分段机制与GDT|LDT

    || 版权声明:本文为博主原创文章,未经博主允许不得转载. 一.前言     在<操作系统篇-浅谈实模式与保护模式>中提到了两种模式,我们说在操作系统中,其实大部分时间是待在保护模式中的. ...

随机推荐

  1. java并发:volatile关键字

    java并发需要保证原子性,可见性,有序性. http://www.cnblogs.com/expiator/p/9226775.html 一.volatile关键字作用如下: 1.volatile关 ...

  2. Openvpn 日常问题解决

    一.Openven的在windows系统下的使用: 1.Openven客户端2.2.0:http://pan.baidu.com/s/1sjJij4T 安装好客户端软件后,将服务器下发的证书和配置文件 ...

  3. SpringMVC入门(基于注解方式实现)

    ---------------------siwuxie095                             SpringMVC 入门(基于注解方式实现)         SpringMVC ...

  4. OC 线程操作 - GCD使用 - 栅栏函数

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ //同步函数无需栅栏函数 //栅栏 ...

  5. VC字符串处理整理

    场景: 1.在存储数据时有时接口需要合并字符串值,并以某些特殊字符来合并部分,到需要的时候再分割它.如一些数值,人名等. 2.C++有strtok,stringstream和find函数来实现分割.可 ...

  6. linux下nginx tomcat集群

    集群系统一般通过两台或多台节点服务器系统通过相应的硬件及软件互连,每个群集节点都是运行其自己进程的独立服务器. 这些进程可以彼此通信,对网络客户机来说就像是形成了一个单一系统,协同起来向用户提供应用程 ...

  7. UI设计初学者如何避免走弯路?

    对于初学UI设计的人而言,可能对UI具体是做什么,或者自己是否能顺利转行胜任这样的岗位存在一定的顾虑,今天我们就来重点说说UI是做什么的,以及想学UI到底要如何避免走弯路,快速的学成. 问题一:UI设 ...

  8. [SoapUI] 比较JSON Response

    比较两个JSON, ID是数字时,处理成统一的格式:只保留小数点后5位 package direct; import org.json.JSONArray; import org.json.JSONE ...

  9. Linux 常用环境变量

    /etc/profile.d/start.sh # java export JAVA_HOME=/usr/local/jdk export CLASSPATH=.:$CLASSPATH:$JAVA_H ...

  10. 用Notepad++在文本文件里快速在每行头尾都加上指定的内容(转载)