Flink定时器实战:处理时间与事件时间

目录

代码解释

[1. 环境设置](#1. 环境设置)

[2. 基于处理时间的定时器](#2. 基于处理时间的定时器)

[3. 基于事件时间的定时器](#3. 基于事件时间的定时器)

[4. 自定义数据源](#4. 自定义数据源)

[5. 任务执行](#5. 任务执行)

背景知识拓展

[1. KeyedProcessFunction](#1. KeyedProcessFunction)

[2. 处理时间(Processing Time)](#2. 处理时间(Processing Time))

[3. 事件时间(Event Time)](#3. 事件时间(Event Time))

[4. 水位线(Watermark)](#4. 水位线(Watermark))

[5. 定时器](#5. 定时器)

[6. Flink 的时间语义](#6. Flink 的时间语义)

[7. Flink 的状态管理](#7. Flink 的状态管理)

[8. Flink 的容错机制](#8. Flink 的容错机制)

进一步学习


Scala 复制代码
package processfunction

import org.apache.flink.streaming.api.functions.source.{RichSourceFunction, SourceFunction}
import org.apache.flink.streaming.api.functions.{KeyedProcessFunction, ProcessFunction}
import org.apache.flink.streaming.api.scala._
import org.apache.flink.util.Collector
import source.{ClickSource, Event}
/**
 *
 * @PROJECT_NAME: flink1.13
 * @PACKAGE_NAME: processfunction
 * @author: 赵嘉盟-HONOR
 * @data: 2023-11-23 23:48
 * @DESCRIPTION
 *
 */
object TimeTimer {
  def main(args: Array[String]): Unit = {
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    env.setParallelism(1)

    val data = env.addSource(new ClickSource).assignAscendingTimestamps(_.timestamp)

    //TODO 基于处理时间的定时器
    data.keyBy(data=>"data").process(new KeyedProcessFunction[String,Event,String] {
      override def processElement(i: Event, context: KeyedProcessFunction[String, Event, String]#Context, collector: Collector[String]): Unit = {
        val currentTime = context.timerService().currentProcessingTime()
        collector.collect("数据到达,当前时间是:"+currentTime)
        context.timerService().registerProcessingTimeTimer(currentTime+5000L)
      }
      override def onTimer(timestamp: Long, ctx: KeyedProcessFunction[String, Event, String]#OnTimerContext, out: Collector[String]): Unit = {
        out.collect("定时器触发,触发时间为:"+timestamp)
      }
    }).print("ProcessingTimeTimer")

    //TODO 基于事件时间的定时器
    val data1=env.addSource(new EventSource).assignAscendingTimestamps(_.timestamp)
    data1.keyBy(data => "data").process(new KeyedProcessFunction[String, Event, String] {
      override def processElement(i: Event, context: KeyedProcessFunction[String, Event, String]#Context, collector: Collector[String]): Unit = {
        val currentTime = context.timerService().currentWatermark()
        collector.collect(s"数据到达,当前时间是:$currentTime ,当前数据时间戳是 ${i.timestamp}")
        context.timerService().registerEventTimeTimer(i.timestamp + 5000L)
      }

      override def onTimer(timestamp: Long, ctx: KeyedProcessFunction[String, Event, String]#OnTimerContext, out: Collector[String]): Unit = {
        out.collect("定时器触发,触发时间为:" + timestamp)
      }
    }).print("EventTimeTimer")

    env.execute("ProcessingTimeTimer")
  }
  class EventSource extends RichSourceFunction[Event] {
    override def run(sourceContext: SourceFunction.SourceContext[Event]): Unit = {
      sourceContext.collect(Event("Mary","./root",100L))
      Thread.sleep(5000L)
      sourceContext.collect(Event("Mary", "./root", 200L))
      Thread.sleep(5000L)
      sourceContext.collect(Event("Mary", "./root", 1000L))
      Thread.sleep(5000L)
      sourceContext.collect(Event("Mary", "./root", 6000L))
      Thread.sleep(5000L)
      sourceContext.collect(Event("Mary", "./root", 6001L))
      Thread.sleep(5000L)
    }

    override def cancel(): Unit = ???
  }
}

这段代码展示了如何使用 Apache Flink 的 KeyedProcessFunction 来实现基于 处理时间(Processing Time)事件时间(Event Time) 的定时器。以下是代码的详细解释和背景知识拓展。


代码解释

1. 环境设置
Scala 复制代码
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(1)
  • StreamExecutionEnvironment.getExecutionEnvironment:获取流处理执行环境。
  • env.setParallelism(1):设置并行度为 1,方便调试和观察结果。
2. 基于处理时间的定时器
Scala 复制代码
val data = env.addSource(new ClickSource).assignAscendingTimestamps(_.timestamp)
data.keyBy(data => "data").process(new KeyedProcessFunction[String, Event, String] {
  override def processElement(i: Event, context: KeyedProcessFunction[String, Event, String]#Context, collector: Collector[String]): Unit = {
    val currentTime = context.timerService().currentProcessingTime()
    collector.collect("数据到达,当前时间是:" + currentTime)
    context.timerService().registerProcessingTimeTimer(currentTime + 5000L)
  }
  override def onTimer(timestamp: Long, ctx: KeyedProcessFunction[String, Event, String]#OnTimerContext, out: Collector[String]): Unit = {
    out.collect("定时器触发,触发时间为:" + timestamp)
  }
}).print("ProcessingTimeTimer")
  • addSource(new ClickSource):从自定义数据源 ClickSource 读取数据。
  • assignAscendingTimestamps(_.timestamp):为数据分配时间戳。
  • keyBy(data => "data"):将所有数据分到同一个 key 中。
  • process:使用 KeyedProcessFunction 处理数据。
    • processElement:处理每条数据,获取当前处理时间,并注册一个 5 秒后的定时器。
    • onTimer:定时器触发时执行的操作。
  • print:打印结果。
3. 基于事件时间的定时器
Scala 复制代码
val data1 = env.addSource(new EventSource).assignAscendingTimestamps(_.timestamp)
data1.keyBy(data => "data").process(new KeyedProcessFunction[String, Event, String] {
  override def processElement(i: Event, context: KeyedProcessFunction[String, Event, String]#Context, collector: Collector[String]): Unit = {
    val currentTime = context.timerService().currentWatermark()
    collector.collect(s"数据到达,当前时间是:$currentTime ,当前数据时间戳是 ${i.timestamp}")
    context.timerService().registerEventTimeTimer(i.timestamp + 5000L)
  }
  override def onTimer(timestamp: Long, ctx: KeyedProcessFunction[String, Event, String]#OnTimerContext, out: Collector[String]): Unit = {
    out.collect("定时器触发,触发时间为:" + timestamp)
  }
}).print("EventTimeTimer")
  • addSource(new EventSource):从自定义数据源 EventSource 读取数据。
  • assignAscendingTimestamps(_.timestamp):为数据分配时间戳。
  • keyBy(data => "data"):将所有数据分到同一个 key 中。
  • process:使用 KeyedProcessFunction 处理数据。
    • processElement:处理每条数据,获取当前水位线(Watermark),并注册一个 5 秒后的定时器。
    • onTimer:定时器触发时执行的操作。
  • print:打印结果。
4. 自定义数据源
Scala 复制代码
class EventSource extends RichSourceFunction[Event] {
  override def run(sourceContext: SourceFunction.SourceContext[Event]): Unit = {
    sourceContext.collect(Event("Mary", "./root", 100L))
    Thread.sleep(5000L)
    sourceContext.collect(Event("Mary", "./root", 200L))
    Thread.sleep(5000L)
    sourceContext.collect(Event("Mary", "./root", 1000L))
    Thread.sleep(5000L)
    sourceContext.collect(Event("Mary", "./root", 6000L))
    Thread.sleep(5000L)
    sourceContext.collect(Event("Mary", "./root", 6001L))
    Thread.sleep(5000L)
  }
  override def cancel(): Unit = ???
}
  • run:模拟数据生成,每隔 5 秒发送一条数据。
  • cancel:取消数据生成(未实现)。
5. 任务执行
Scala 复制代码
env.execute("ProcessingTimeTimer")
  • 启动 Flink 任务。

背景知识拓展

1. KeyedProcessFunction
  • 作用:用于处理 keyed 数据流,支持状态管理和定时器。
  • 核心方法
    • processElement:处理每条数据。
    • onTimer:定时器触发时执行的操作。
2. 处理时间(Processing Time)
  • 定义:数据被处理时的系统时间。
  • 特点:简单、高效,但无法处理乱序事件。
  • 应用场景:对实时性要求高,但对事件顺序不敏感的场景。
3. 事件时间(Event Time)
  • 定义:数据实际发生的时间。
  • 特点:能处理乱序事件,但需要水位线(Watermark)机制。
  • 应用场景:对事件顺序敏感的场景,如日志分析、交易监控。
4. 水位线(Watermark)
  • 作用:用于处理乱序事件,标记事件时间的进度。
  • 生成方式:通常基于事件时间戳生成。
  • 延迟处理:允许一定时间范围内的延迟数据。
5. 定时器
  • 类型
    • 处理时间定时器:基于系统时间触发。
    • 事件时间定时器:基于事件时间触发。
  • 注册方式 :通过 context.timerService().registerProcessingTimeTimercontext.timerService().registerEventTimeTimer 注册。
  • 处理时间(Processing Time):数据被处理时的系统时间。
  • 事件时间(Event Time):数据实际发生的时间。
  • 摄入时间(Ingestion Time):数据进入 Flink 系统的时间。
  • Keyed State :与 key 绑定的状态,如 ValueStateListState
  • Operator State :与算子绑定的状态,如 ListStateBroadcastState
  • 状态后端(State Backend) :用于存储状态,如 MemoryStateBackendRocksDBStateBackend
  • Checkpoint:定期保存状态,用于故障恢复。
  • Savepoint:手动触发的状态保存,用于版本升级或任务迁移。

进一步学习

通过这段代码的学习,你可以掌握如何使用 Flink 的 KeyedProcessFunction 实现处理时间和事件时间的定时器,并了解 Flink 的时间语义、水位线机制以及状态管理等核心概念。

相关推荐
ChoSeitaku2 小时前
Git的安装|创建仓库|配置Git|添加文件|修改文件|版本回退|撤销修改|删除文件
大数据·git·elasticsearch
T06205143 小时前
上市公司-创新数据汇总指标(创新投入、创新产出、创新效率)(2006-2024年)
大数据
卡梅德生物科技3 小时前
卡梅德生物科普:CD140a(PDGFRα)靶点深度解析:机制、药物研发与未来趋势
大数据·人工智能·面试·职场和发展·学习方法
funkygroove3 小时前
研发与市场决策难题解析:如何用结构化数据破解信息不对称
大数据·医药数据库
howard20053 小时前
1.1.4 Scala的使用方式
scala·交互方式·文件方式
IT研究所3 小时前
从工单到智能分析:AIGC运维助手应用价值
大数据·运维·数据库·人工智能·科技·低代码·自动化
正在走向自律3 小时前
大数据时代时序数据库选型指南:Apache IoTDB为何成为工业物联网首选
大数据·时序数据库·iotdb
生活予甜3 小时前
MINISH科技宣布迈向健康科技企业的新阶段
大数据·人工智能·科技
V搜xhliang02463 小时前
自然语言理解与语音识别(ASR)
大数据·人工智能·机器学习·自然语言处理·机器人·语音识别·xcode