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. Segments(叉积)

    Segments http://poj.org/problem?id=3304 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: ...

  2. python学习——urlparse模块

    urlparse模块: 1.urlparse() 具体程序及结果如下: >>> url = 'http://i.cnblogs.com/EditPosts.aspx?opt=1'&g ...

  3. 迭代器&生成器&yield异步

    迭代器 #迭代器是访问集合元素的一种形式,迭代器从集合的第一个元素开始访问,直到所有的元素被访问# 结束才结束,迭代器只能往前访问,不能往后访问,比如你先访问1,在访问2,在访问3.如果已经# 访问到 ...

  4. OC线程操作-GCD介绍

    1. GCD介绍 1.11.2 1.3 异步具备开启能力但是不是 一定可以开启 1.4 1.5 67. 8.

  5. VMware安装centos虚拟机 通过NAT与主机互通并能上网

    1.关于centos虚拟机的安装,我这里就不详细说明了,网上有很多教程,默认你们已经安装好.       (我的环境是centos6.6 x86 最小安装版) 2.右键虚拟主机,选择设置选项. 3.在 ...

  6. linux-centos6-rabbitmq安装及配置

    服务器版本centos6.8 一.先安装Erlang 具体安装哪个版本可以对照 http://www.rabbitmq.com/which-erlang.html 如下图: 准备安装RabbitMQ3 ...

  7. 为什么二代测序的原始数据中会出现Read重复现象?

    为什么二代测序的原始数据中会出现Read重复现象? 要搞清楚这个read重复(duplicate)的问题,我想我们需要从NGS数据的产出过程说起,具体来说如下: 基因组DNA提取: DNA随机打断,最 ...

  8. ubuntu下常用操作

    屏幕截图: 可以用ubuntu自带的截图软件:gnome-screenshot. 该工具截图区域并且复制到剪切板命令为  gnome-screenshot -c -a,可以给该命令添加快捷方式,alt ...

  9. 用pyqt5做一个能python程序能插入图片的ide

    之前只是放到github上了,现在一想应该开源,大家想继续做好这个ide的都能从这里起步. #注意在.py文件相同目录下放一个1.png做测试图片 #本质就是用html来实现图片 #写在前面的话:这个 ...

  10. part1:15-安装Linux系统到开发板

    1.Qtopia简介 Qtopia是Trolltech公司为采用嵌入式Linux操作系统的消费电子设备而开发的综合应用平台,Qtopia包含完整的应用层.灵活的界面用户.窗口操作系统.应用程序启动程序 ...