我正在使用广播模式来连接两个流,并将数据从一个流读取到另一个流。代码看起来像这样
case class Broadcast extends BroadCastProcessFunction[MyObject,(String,Double), MyObject]{
override def processBroadcastElement(in2: (String, Double),
context: BroadcastProcessFunction[MyObject, (String, Double), MyObject]#Context,
collector:Collector[MyObject]):Unit={
context.getBroadcastState(broadcastStateDescriptor).put(in2._1,in2._2)
}
override def processElement(obj: MyObject,
readOnlyContext:BroadCastProcessFunction[MyObject, (String,Double),
MyObject]#ReadOnlyContext, collector: Collector[MyObject]):Unit={
val theValue = readOnlyContext.getBroadccastState(broadcastStateDesriptor).get(obj.prop)
//If I print the context of the state here sometimes it is empty.
out.collect(MyObject(new, properties, go, here))
}
}
状态描述符:
val broadcastStateDescriptor: MapStateDescriptor[String, Double) = new MapStateDescriptor[String, Double]("name_for_this", classOf[String], classOf[Double])
我的执行代码如下。
val streamA :DataStream[MyObject] = ...
val streamB :DataStream[(String,Double)] = ...
val broadcastedStream = streamB.broadcast(broadcastStateDescriptor)
streamA.connect(streamB).process(new Broadcast)
问题出在processElement
函数中,状态有时为空,有时为空。由于我不断从我知道它具有数据的文件中进行流式传输,因此状态应始终包含数据。我不明白为什么它会刷新状态并且无法获取数据。
在将数据置于状态之前和之后,我尝试在processBroadcastElement
中添加一些打印内容,结果如下:
0 - 1
1 - 2
2 - 3
.. all the way to 48 where it resets back to 0
更新: 我注意到的事情是,当我减小流执行上下文的超时值时,结果会好一些。当我增加它时,地图总是空的。
env.setBufferTimeout(1) //better results
env.setBufferTimeout(200) //worse result (default is 100)
答案 0 :(得分:0)
每当在Flink中连接两个流时,您就无法控制Flink将事件从两个流传递到用户函数的时间。因此,例如,如果有一个事件可从streamA处理,而有一个事件可从streamB处理,则接下来可以处理其中任何一个。您不能期望广播的流以某种方式优先于其他流。
根据您的要求,可以采用多种策略来应对两个流之间的竞争。例如,您可以使用KeyedBroadcastProcessFunction并使用其applyToKeyedState方法在新的广播事件到达时迭代所有现有的键控状态。
答案 1 :(得分:0)
正如David提到的那样,该作业可能正在重新启动。我禁用了检查点,因此可以看到引发任何可能的异常,而不是flink静默失败并重新启动作业。
原来,尝试解析文件时出错。因此,作业不断重新启动,因此状态为空,而flink不断重复消耗流。