现在有个需求是需要计算当前月初到当前时间之间的数据,现有窗口貌似都无法满足这个需求
当我们在使用Flink的时候,避免不了要和时间(time)、水位线(watermarks)打交道,理解这些概念是开发分布式流处理应用的基础。那么Flink支持哪些时间语义?Flink是如何处理乱序事件的?什么是水位线?水位线是如何生成的?水位线的传播方式是什么?让我们带着这些问题来开始本文的内容。
时间语义
基本概念
时间是Flink等流处理中最重要的概念之一,在 Flink 中 Time 可以分为三种:Event-Time,Processing-Time 以及 Ingestion-Time,如下图所示:
Event Time
事件时间,事件(Event)本身的时间,即数据流中事件实际发生的时间,通常使用事件发生时的时间戳来描述,这些事件的时间戳通常在进入流处理应用之前就已经存在了,事件时间反映了事件真实的发生时间。所以,基于事件时间的计算操作,其结果是具有确定性的,无论数据流的处理速度如何、事件到达算子的顺序是否会乱,最终生成的结果都是一样的。
Ingestion Time
摄入时间,事件进入Flink的时间,即将每一个事件在数据源算子的处理时间作为事件时间的时间戳,并自动生成水位线(watermarks,关于watermarks下文会详细分析)。
Ingestion Time从概念上讲介于Event Time和Processing Time之间。与Processing Time相比 ,它的性能消耗更多一些,但结果却更可预测。由于 Ingestion Time使用稳定的时间戳(在数据源处分配了一次),因此对记录的不同窗口操作将引用相同的时间戳,而在Processing Time中每个窗口算子都可以将记录分配给不同的窗口。
与Event Time相比,Ingestion Time无法处理任何乱序事件或迟到的数据,即无法提供确定的结果,但是程序不必指定如何生成水位线。在内部,Ingestion Time与Event Time非常相似,但是可以实现自动分配时间戳和自动生成水位线的功能。
Processing Time
处理时间,根据处理机器的系统时钟决定数据流当前的时间,即事件被处理时当前系统的时间。还以窗口算子为例(关于window,下文会详细分析),基于处理时间的窗口操作是以机器时间来进行触发的,由于数据到达窗口的速率不同,所以窗口算子中使用处理时间会导致不确定的结果。在使用处理时间时,无需等待水位线的到来后进行触发窗口,所以可以提供较低的延迟。
对比
经过上面的分析,应该对Flink的时间语义有了大致的了解。不知道你会不会有这样一个疑问:既然事件时间已经能够解决所有的问题了,那为何还要用处理时间呢?其实处理时间有其特定的使用场景,处理时间由于不用考虑事件的延迟与乱序,所以其处理数据的延迟较低。因此如果一些应用比较重视处理速度而非准确性,那么就可以使用处理时间,比如要实时监控仪表盘。总之,虽然处理时间的延迟较低,但是其结果具有不确定性,事件时间虽然有延迟,但是能够保证处理的结果具有准确性,并且可以处理延迟甚至无序的数据。
使用
上一小结讲述了三种时间语义的基本概念,接下来将从代码层面讲解在程序中该如何配置这三种时间语义。首先来看一段代码:
/** The time characteristic that is used if none other is set. */
private static final TimeCharacteristic DEFAULT_TIME_CHARACTERISTIC = TimeCharacteristic.ProcessingTime;
//省略的代码
/** The time characteristic used by the data streams. */
private TimeCharacteristic timeCharacteristic = DEFAULT_TIME_CHARACTERISTIC;
上述两行代码摘自StreamExecutionEnvironment类,可以看出,Flink在流处理程序中默认的时间语义是Processing Time,那么该如何修改默认的时间语义呢?很简单,再来看一段代码,下面的代码片段同样来自于StreamExecutionEnvironment类:
/**
如果使用Processing Time或者Event Time,默认的水位线间隔时间是200毫秒
可以通过ExecutionConfig#setAutoWatermarkInterval(long)设置
@param characteristic The time characteristic.
*/
@PublicEvolving
public void setStreamTimeCharacteristic(TimeCharacteristic characteristic) {
this.timeCharacteristic = Preconditions.checkNotNull(characteristic);
if (characteristic == TimeCharacteristic.ProcessingTime) {
getConfig().setAutoWatermarkInterval(0);
} else {
getConfig().setAutoWatermarkInterval(200);
}
}
上述的方法可以配置不同的时间语义,参数TimeCharacteristic是一个枚举类,包括ProcessingTime,IngestionTime,EventTime三个元素。具体使用方式如下:
//env.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime);
//env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime); ———————————————— 协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_39533361/article/details/111743920
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。