Flink的时间(Time)机制

乱序问题

某数据源中的某些数据由于某种原因会有5秒的延迟,也就是在实际时间的第1秒产生的数据有可能5秒中产生的数据之后到来,如何让这个延迟的数据回到正确的顺序位置;

Time类型:

Time是Flink中重要概念之;关于Apache Flink中有如下三种时间类型:

  • Processing Time : 处理时间,当前机器处理该事件的时间(即进入某个算子时的系统时间),有着最好的性能和最低的延迟
  • Ingestion Time : 摄入时间,数据进入Flink框架的时间,在Source Operator中设置,每个事件拿到当前时间作为时间戳,后续的时间窗口基于该时间;相比ProcessingTime可以提供更可预测的结果
  • Event Time : 事件时间是每条事件在它产生的时候记录的时间,该时间记录在事件中,在处理的时候可以被提取出来;事件事件对于乱序、延时、或者数据重放等情况,都能给出正确都结果,事件时间依赖于事件本身,而跟物理时钟没有关系,利用事件时间编程必须如何制定如何生成事件时间的watermark;
    • 事件时间存在一定的延时,因此自然的需要延时和无序事件等待一段时间;因此,使用事件时间编程通常需要与处理时间相结合;

Setting a Time Characteristic(设置时间特性)

Flink程序的第一部分工作通常是设置时间特性,该设置用于定义数据用什么时间,在时间窗口处理中使用什么时间;

下面的例子展示流一个flink程序在1h的时间窗口中的聚合操作,窗口的操作取决于时间特性;

final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime);

// alternatively:
// env.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime);
// env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);

DataStream stream = env.addSource(new FlinkKafkaConsumer09(topic, schema, props));

stream
    .keyBy( (event) -> event.getUser() )
    .timeWindow(Time.hours(1))
    .reduce( (a, b) -> a.add(b) )
    .addSink(...);

如果使用事件时间来运行该程序,程序不仅需要直接定义事件的事件时间,还需要发送一个watermark,或者在数据源之后需要注入一个**时间戳分配方法和watermark生成方法;**这些方法描述怎么获取事件时间,以及时间流展示的乱序程度;

WaterMark

watermark是一种衡量Event Time进展的机制,它是数据本身的一个隐藏属性;通常基于Event Time的数据,自身都包含一个timestamp.watermark;是用于处理乱序事件的,而正确的处理乱序事件,通常用watermark机制结合window来实现;

我们知道,流处理从事产生,到流进source,再到operator,中间是有一个过程和时间;但是也不排除由于网络,背压等原因,导致乱序的产生(out-of-order或者说late element);但是对于late element,我们又不能无限期等下去,必须要有个机制来保证一个特定的时间后,必须触发window去进行计算,此时就是watermark发挥作用来,它表示了当达到watermark到达后,在watermark之前的数据已经全部达到(即使后面还有延迟数据).

Flink的时间(Time)机制_第1张图片

WaterMark介绍:

Watermark是Flink上为了处理EventTime时间类型的窗口计算提出的一种机制,本质上也是一种时间戳;WaterMark是用于处理乱序事件的,而正确的处理乱序事件,通常用watermark机制结合window来实现;

  • 当operator通过Event Time的时间窗口来处理数据时,它必须在确定所有属于该时间窗口的消息全部流入此操作符后,才能开始处理数据,但是由于消息可能是乱序的,所以operator无法直接确认任何所有属于该时间窗口的消息全部流入此操作符;
  • WaterMark包含一个时间戳,Flink使用WaterMark保证所有小于该时间戳的消息都已流入,Flink的数据源在确认所有小于该时间戳的消息都已流入,Flink的数据源在确认所有小于某个时间戳的消息都已输出到Flink流处理器后,会生成一个包含该时间戳的WaterMark,插入到消息流中输出到Flink流处理系统中;
  • Flink operator算子按照时间窗口缓存所有流入的消息,当操作符处理到WaterMark时,它对所有小于该WaterMark时间戳的时间窗口的数据进行处理并发送到下一个操作符节点,然后也将WaterMark发送到下一个操作符节点;
  • 一旦一个watermark到达了operator,operator可以将内部事件时间提前到watermark的时间戳

WaterMark跟事件一样在流中传输,并且携带一个时间戳t,一个watermark(t)声明了从该处开始流中应该不存在时间戳T’’<=t的元素

各个时间窗口的数据,什么时候触发计算

  • watermark时间 >= window_endTtime
    watermark是怎么产生的
  • 在[window_startTime, window_endTtime)中有数据存在;

需要注意的两点

  • 因为数据到达并不是循环的,注意保存一个当前最大时间戳作为Watermark时间;
  • 并行同步问题

Watermarks in Parallel Streams(并行数据流)

  • watermark在source处或者之后生成,source的每个并行子任务都会独立生成自己的watermark;这些watermarks定义流特定并行sorce的事件时间;
  • watermark流经operator的时候,会将该operator的事件时间向前推进,当一个operator的事件时间被推前,它会为后续的operator生成一个新的watermark;
  • 一些operator有多个输入流:例如一个union操作和keyby操作,这些operator的当前事件时间是各个流的最小事件时间,随着流入流中事件时间更新,该operator的事件时间也会更新;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X8uXyFQV-1573738426933)(https://ci.apache.org/projects/flink/flink-docs-release-1.9/fig/parallel_streams_watermarks.svg)]

Late Elements

某些事件(t’)可能违背watermark的条件;也就是说晚于watermark(t)到达,但是事件时间在watermark之前(t’小于t);实际运行过程中,事件可能被延迟任意时间,所以不可能指定一个时间,保证该时间之前没,所有事件都被处理,而且即使可以限制延迟,通常也不希望将watermark延迟太多,因为这会导致事件时间窗口的处理延迟过多;

Watermark的产生方式:

  • Punctuated:数据流中每一个递增的EventTime都会产生一个Watermark;在实际的生产中Punctuated方式在TPS很高的场景下会产生大量的Watermark在一定程度上对下游算子造成压力,所以只有在实时性要求非常高的场景才会选择Punctuated的方式进行Watermark的生成;

  • Periodic:周期性的(一定时间间隔或者达到一定的记录条数)产生一个Watermark;在实际的生成中Periodic的方式必须结合时间和积累条数两个维度继续周期性的产生Watermark,否则在极端情况下会有很大的延时;

你可能感兴趣的:(Flink,大数据)