我正在尝试实现一个Spark Streaming管道,它能够在不使用updateStateByKey / mapWithState的情况下跨批处理维护状态。我知道文档说明这些原语是推荐的方式,但我的任务是寻找替代解决方案。
应用程序需要保留一个缓存,该缓存由每个批次(来自Kinesis流)中显示的数据以及从Couchbase存储中检索的数据组成。
我带来了一个大致用以下伪代码描述的实现:
上下文:
streamData <- data from Kinesis Stream
cache <- Empty Dataset
cacheEmpty <- true
forEachRDD (streamData) {
if (cacheEmpty) {
cache <- warmupCache()
cacheEmpty <- false
}
else {
cache <- updateCache()
}
workingSet <- getWorkingSetFromCache(cache)
output(workingSet)
}
正如您所看到的,我使用forEachRDD(在驱动程序的进程空间中)更新缓存数据集,该数据集基本上随每个批处理更新。缓存是在forEachRDD之外声明的数据集变量。
我遇到的问题是,虽然我正在检查缓存(以避免血统不断增长),但在每个后续批处理中,Spark作业执行的任务数量都在增加,看起来Spark似乎是跟踪DAG中的状态到缓存变量的第一个状态(开始为空),因此处理每个批处理所需的时间随着每个批处理而增加,并且管道最终因堆栈溢出异常而崩溃。
有没有办法避免这种行为,或者我只是根据Spark内部的工作方式采用徒劳的方法?
任何帮助都将深受赞赏。
谢谢, -Eduardo。