文章目录
- 时间语义
- 水位线(Watermarks)
时间语义
对于流式数据处理,最大的特点就是数据上具有时间的属性特征,Flink根据时间产生的位置不同,将时间区分为如下三种时间概念
- 事件时间(Event Time):数据流事件实际发生的时间。
- 接入时间(Ingestion Time):数据进入Flink系统的时间。
- 处理时间(Processing Time):当前流处理算子所在机器上的本地时钟时间。
时间与事件的关系
Flink中 默认使用的是处理时间,但是在大多数情况下都会使用事件时间** (即实际事件的发生点,也符合事件发生进而分析的逻辑),一般只有在Event Time无法使用的情况下才会使用接入时间和处理时间,因此我们可以通过调用执行环境的setStreamTimeCharacteristic
方法来指定时间语义
//创建执行环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
//设置指定的时间语义,如下面的设置为EventTime
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
处理时间与事件时间的选择
在大部分场景由于我们需要依据事件发生的顺序来进行逻辑处理,因此都会使用事件时间。但是在一些特殊场景下,考虑到事件数据数据乱序到达以及延迟到达等问题,为了保证实时性和低延迟,处理时间就会派上用场。
例如下面几种场景:
- 更重视处理速度而非准确性的应用。
- 需要周期性实时报告结果而无论其准确性(如实时监控仪表盘)。
因此,对比处理时间和事件时间得出结论:
- 处理时间提供了低延迟,但是它的结果依赖处理速度,因此具有不确定性。
- 事件时间则与之相反,能够保证结果的准确性,并允许你处理延迟甚至无序的事件。
水位线(Watermarks)
在理想状态下,事件数据都是按照事件产生的时间顺序传输至Flink系统中。但事实上,由于网络或者分布式系统等外部因素的影响下,事件数据往往不能及时传输,导致系统的不稳定而造成数据乱序到达或者延迟到达等情况。
乱序数据的影响
一旦出现这种问题,如果我们严格按照Event Time来决定窗口的运行,我们既不能保证属于该窗口的数据已经全部到达,也不能无休止的等待延迟到达的数据,因此我们需要一种机制来控制数据处理的进度,这就是水位线(Watermarks)机制。
水位线是一个全局的进度指标,它能够衡量数据处理进度 (表达数据到达的完整性),保证事件数据全部到达Flink系统,即使数据乱序或者延迟到达,也能够像预期一样计算出正确和连续的结果。
那么它是如何做到的呢?
- Flink会使用最新的事件时间减去固定时间间隔作为水位线,该时间时间为用户外部配置的支持最大延迟到达的时间长度。
- 当一个算子接收到一个时间为T的水位线,就可以认为不会再收到任何时间戳小于或等于T的事件了(迟到事件或异常事件)
- 水位线其实就相当于一个提示算子的信号,当水位线时间戳大于时间窗口的结束时间,且窗口中含有事件数据时,此时算子就会认为某个特定时间区间的时间戳已经全部到齐,立即开始触发窗口计算或对接收的数据进行排序。
从上面我们可以看出,水位线其实就是在结果的准确性和延迟之间做出取舍,它虽然保证了低延迟,但是伴随而来的却是低可信度。倘若我们要保证后续的延迟事件不丢失,就必须额外增加一些代码来处理他们,但是如果采用这种保守的机制,虽然可信度低高了,但是延迟又会继续增加,因此延迟和可信无法做到两全其美,需要我们依据具体场景来自己平衡。