flink的ProcessFunction API(底层 API)

需知

我们之前学习的转换算子是无法访问事件的时间戳信息和水位线信息的。而这 在一些应用场景下,极为重要。
例如 MapFunction 这样的 map 转换算子就无法访问时间戳或者当前事件的事件时间
基于此,DataStream API 提供了一系列的 Low-Level 转换算子。可以访问时间戳、watermark 以及注册定时事件。还可以输出特定的一些事件,例如超时事件等。 Process Function 用来构建事件驱动的应用以及实现自定义的业务逻辑(使用之前的 window 函数和转换算子无法实现)。例如,Flink SQL 就是使用 Process Function 实 现的。Flink 提供了 8 个 Process Function:

 ProcessFunction 
 KeyedProcessFunction 
 CoProcessFunction 
 ProcessJoinFunction 
 BroadcastProcessFunction 
 KeyedBroadcastProcessFunction
 ProcessWindowFunction
 ProcessAllWindowFunction

KeyedProcessFunction

这里我们重点介绍 KeyedProcessFunction。 KeyedProcessFunction 用来操作 KeyedStream(也就是前面必须有keyby操作才能使用)。KeyedProcessFunction 会处理流 的每一个元素,输出为 0 个、1 个或者多个元素。
所有的 Process Function 都继承自 RichFunction 接口,所以都有 open()、close()和 getRuntimeContext()等方法。而 KeyedProcessFunction[KEY, IN, OUT]还额外提供了两个方法: processElement(v: IN, ctx: Context, out: Collector[OUT]), 流中的每一个元素 都会调用这个方法,调用结果将会放在 Collector 数据类型中输出。
Context 可以访问元素的时间戳,元素的 key,以及 TimerService 时间服务Context 还可以将结果输出到别的流(side outputs)。 onTimer(timestamp: Long, ctx: OnTimerContext, out: Collector[OUT])是一个回 调函数。当之前注册的定时器触发时调用。参数 timestamp 为定时器所设定 的触发的时间戳。Collector 为输出结果的集合。OnTimerContext 和 processElement 的 Context 参数一样,提供了上下文的一些信息,例如定时器 触发的时间信息(事件时间或者处理时间)。

TimerService 和 定时器(Timers)

Context 和 OnTimerContext 所持有的 TimerService 对象拥有以下方法:
currentProcessingTime(): Long 返回当前处理时间 currentWatermark(): Long 返回当前 watermark 的时间戳 registerProcessingTimeTimer(timestamp: Long): Unit 会注册当前 key 的 processing time 的定时器。当 processing time 到达定时时间时,触发 timer。
registerEventTimeTimer(timestamp: Long): Unit 会注册当前 key 的 event time 定时器。当水位线大于等于定时器注册的时间时,触发定时器执行回调函数。 deleteProcessingTimeTimer(timestamp: Long): Unit 删除之前注册处理时间定 时器。如果没有这个时间戳的定时器,则不执行
deleteEventTimeTimer(timestamp: Long): Unit 删除之前注册的事件时间定时 器,如果没有此时间戳的定时器,则不执行。 当定时器 timer 触发时,会执行回调函数 onTimer()。注意定时器 timer 只能在 keyed streams 上面使用。

应用场景:

在电商商品购买过程中有这样一些场景:用户点击下单,此时订单处于待支付状态,如果在2小时之后还处于待支付状态那么就将这笔订单取消,置为取消状态;用户收货之后可以对商品进行评价,如果在24小时内仍然没有评价,那么自动将用户对商品的评分设置为5星….等等,这样的场景都可以称之为延时处理场景,当数据发送出去了,不立刻进行处理,而是等待一段时间之后在处理,目前对于延时处理的方案也有很多,例如:

  1. java中DelayQueue 内部使用优先级队列方式存储消息体,存放的消息体实现Dealy接口,然后使用一个线程不断消费队列数据。
  2. redis中SortedSet
    借助Redis的SortedSet数据结构,使用时间作为排序的方式,外部使用一个线程不断轮询该SortedSet。
  3. 定时扫描数据库 将延时触发的任务信息存储在数据库中,然后使用线程去轮序查询符合要求触发的定时任务。

……

在流处理中也经常会有一些定时触发的场景,例如定时监控报警等,并且时间窗口的触发也是通过延时调用触发,接下来了解flink中是如何实现延时处理。

你可能感兴趣的:(flink)