目前,我正在使用Flink对流处理引擎进行研究。对于我的研究,我使用历史流,其中包含以下形式的元组:
event_time, attribute_1, ..., attribute_X
其中event_time
在处理过程中用作TimeCharacteristic.EventTime
。此外,我通过以下任一方式将数据集推送到处理拓扑中:(i)创建内存中结构,或(ii)通过读取CSV文件本身。
不幸的是,我注意到即使有足够的元组到达完成一个完整窗口的窗口操作符,该窗口也不会被推送到下游进行处理。结果,性能显着下降,并且很多次我有OutOfMemoryError
异常(具有大型历史流)。
为了说明典型的用例,我提供以下示例:
StreamExecutionEnvironment env =
StreamExecutionEnvironment.createLocalEnvironment();
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
env.setParallelism(1);
env.setMaxParallelism(1);
List<Tuple2<Long, Integer>> l = new ArrayList<>();
l.add(new Tuple2<>(1L, 11));
l.add(new Tuple2<>(2L, 22));
l.add(new Tuple2<>(3L, 33));
l.add(new Tuple2<>(4L, 44));
l.add(new Tuple2<>(5L, 55));
DataStream<Tuple2<Long, Integer>> stream = env.fromCollection(l);
stream.assignTimestampsAndWatermarks(
new AscendingTimestampExtractor<Tuple2<Long, Integer>>() {
@Override
public long extractAscendingTimestamp(Tuple2<Long, Integer> t) {
return t.f0;
}
})
.windowAll(SlidingEventTimeWindows.of(Time.milliseconds(2),
Time.milliseconds(1)))
.sum(1)
.print();
env.execute();
根据l
的内容,我需要有以下窗口结果:
每个列表项可以读作[start-timestamp,end-timestamp),Sum:X.
我希望Flink每次出现一个时间戳超出打开窗口结束时间戳的元组时都会产生一个窗口化结果。例如,我希望当带有时间戳4L
的元组被送入窗口运算符时,会产生窗口[1,3]的求和。但是,当l
中的所有元组都被推入流的拓扑中时,处理启动。当我使用较大的历史流时会发生同样的事情,这会导致性能下降(甚至耗尽内存)。
问题:如何在窗口完成时强制Flink将窗口推送到下游进行处理?
我相信对于SlidingEventTimeWindows
,用水印触发了窗口的驱逐。如果前一个是真的,我如何编写拓扑结构,以便在具有更晚时间戳的元组到达时触发窗口?
谢谢
答案 0 :(得分:1)
AscendingTimestampExtractor
使用定期水印策略,其中Flink将每n毫秒调用getCurrentWatermark()
方法,其中n是autowatermarkinterval。
默认间隔为200毫秒,与窗口大小相比非常长。但是,它们不能直接比较 - 200毫秒是在处理时间而非事件时间内测量的。不过,我怀疑如果你没有改变这个配置设置,那么在发出第一个水印之前会创建很多窗口,我想这会解释你所看到的。
您可以减少自动水印间隔(可能为1毫秒)。或者您可以实施AssignerWithPunctuatedWatermarks,这将为您提供更多控制权。