Flink之Trigger与Evictor

一、概述

在Flink中,使用event-time模式时,默认提供的window有TumblingEventTimeWindows,SlidingEventTimeWindows,EventTimeSessionWindow等,其中这些是属于window operator中的一部分,称作 window assigner。window operator包含四个组件,除了 window assigner外,还包括 trigger , evictor, window process。其作用分别如下:

  • window assigner 指明数据流中的数据属于哪个window
  • trigger 指明在哪些条件下触发window计算,基于处理数据时的时间以及事件的特定属性、
  • evictor 可选组件,在window执行计算前或后,将window中的数据移除,如使用
  • globalWindow时,由于该window的默认trigger为永不触发,所以既需要实现自定义trigger,也需要实现evictor,移除部分已经计算完毕的数据。
    window process flink默认提供的有 ReduceFunction,AggragateFunction.还可以自定义实现 windowProcessFunction

二、Trigger 触发器

  • 窗口触发器,决定了窗口什么时候使用窗口函数处理窗口内元素。每个窗口分配器都带有一个默认的触发器。
  • TriggerResult四个值:CONTINUE、FIRE、FIRE_AND_PURGE、PURGE;
    FIRE、FIRE_AND_PURGE区别:FIRE触发计算不清空窗口数据,FIRE_AND_PURGE:触发计算并清空窗口数据;
    如果后面的Function等计算用户自己增量维护状态,可以只接受增量数据则使用FIRE_AND_PURGE;
  • FIRE之后的Function中会受到整个窗口的数据而FIRE_AND_PURGE只会收到增量数据,特别是在一些大窗口大数据量案例中不清理数据可能会oom
  • Flink带有一些内置触发器:
    EventTimeTrigger 窗口默认的Triiger,根据 watermarks 度量的事件时间进度进行触发。
    ProcessingTimeTrigger 窗口默认的Triiger,基于处理时间触发。
    CountTrigger 一旦窗口中的元素数量超过给定限制就会触发,FIRE不清理数据。
    ContinuousEventTimeTrigger 每隔一段时间触发,FIRE不清理数据。
    PurgingTrigger 将其作为另一个触发器的参数,并将其转换为带有清除功能(transforms it into a purging one)。

如下代码展示了,每条数据触发一次计算并清空窗口数据

class UtcTrigger() extends Trigger[MyTime, TimeWindow] {
  //当每个元素被添加窗口时调用
  override def onElement(t: MyTime, l: Long, w: TimeWindow, triggerContext: Trigger.TriggerContext): TriggerResult = {
    println("触发器onElement")
    TriggerResult.FIRE_AND_PURGE
  }

  //当注册的处理时间计时器被触发时调用
  override def onProcessingTime(l: Long, w: TimeWindow, triggerContext: Trigger.TriggerContext): TriggerResult = {
    println("触发器onProcessingTime")
    TriggerResult.CONTINUE
  }

  //当注册的事件时间计时器被触发时调用
  override def onEventTime(l: Long, w: TimeWindow, triggerContext: Trigger.TriggerContext): TriggerResult = {
    println("触发器onEventTime")
    TriggerResult.FIRE_AND_PURGE
  }

  //在清除(removal)窗口时调用
  override def clear(w: TimeWindow, triggerContext: Trigger.TriggerContext): Unit = {
    println("触发器clear")
  }
}

三、Evictor 驱逐器

  • Flink 窗口模型还允许在窗口分配器和触发器之外指定一个可选的驱逐器(Evictor)。
    可以使用 evictor(…) 方法来完成。
  • 驱逐器能够在触发器触发之后,窗口函数使用之前或之后从窗口中清除元素。
    evictBefore()在窗口函数之前使用。而 evictAfter() 在窗口函数之后使用。
    在使用窗口函数之前被逐出的元素将不被处理。
  • Flink带有三种内置驱逐器:
    CountEvictor:在窗口维护用户指定数量的元素,如果多于用户指定的数量,从窗口缓冲区的开头丢弃多余的元素。
    DeltaEvictor:使用 DeltaFunction 和一个阈值,来计算窗口缓冲区中的最后一个元素与其余每个元素之间的差值,并删除差值大于或等于阈值的元素。
    TimeEvictor:以毫秒为单位的时间间隔(interval)作为参数,对于给定的窗口,找到元素中的最大的时间戳max_ts,并删除时间戳小于max_ts - interval的所有元素。
  • 默认情况下,所有内置的驱逐器在窗口函数之前使用。指定驱逐器可以避免预聚合(pre-aggregation),因为窗口内所有元素必须在窗口计算之前传递给驱逐器。
  • Flink 不保证窗口内元素的顺序。这意味着虽然驱逐器可以从窗口开头移除元素,但这些元素不一定是先到的还是后到的。
class MyEvictor() extends Evictor[MyTime, TimeWindow] {
  override def evictBefore(iterable: lang.Iterable[TimestampedValue[MyTime]], i: Int, w: TimeWindow, evictorContext: Evictor.EvictorContext): Unit = {
    val ite: util.Iterator[TimestampedValue[MyTime]] = iterable.iterator()
    while (ite.hasNext) {
      val elment: TimestampedValue[MyTime] = ite.next()
      //指定事件事件获取到的就是事件时间
      println("驱逐器获取到的时间:" + elment.getTimestamp)
      //模拟去掉非法参数数据
      if (elment.getValue.timestamp <= 0) {
        ite.remove()
      }
    }
  }

  override def evictAfter(iterable: lang.Iterable[TimestampedValue[MyTime]], i: Int, w: TimeWindow, evictorContext: Evictor.EvictorContext): Unit = {

  }
}

你可能感兴趣的:(flink)