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 的时间语义、水位线机制以及状态管理等核心概念。

相关推荐
折哥的程序人生 · 物流技术专研1 天前
效率翻倍:出版社多库区复合型 ABC 仓储拣选体系全解(含直发/越库/箱式立库/托盘立库)
大数据
Elastic 中国社区官方博客1 天前
Elasticsearch:智能搜索 - AI builder 及 skills
大数据·人工智能·elasticsearch·搜索引擎·ai·信息可视化·全文检索
阿里云大数据AI技术1 天前
Agentic风控:Flink+Fluss+大模型构建Agent全链路风险感知与实时告警
人工智能·flink
跨境摸鱼1 天前
低价模型承压阶段跨境品牌如何把重心转向复购与客单
大数据·人工智能·跨境电商·亚马逊·跨境
果汁华1 天前
LangGraph:构建状态化 AI 代理的革命性编排框架
大数据·人工智能
面向Google编程1 天前
从零学习Kafka:生产者分区机制
大数据·kafka
盘古信息IMS1 天前
全域场景重构,激活智造新未来!盘古信息机加行业数智化解决方案深度解析
大数据·人工智能
跨境卫士-小汪1 天前
多国站点利润分化加剧跨境卖家如何重新排优先级
大数据·人工智能·产品运营·跨境电商·跨境
精益数智工坊1 天前
物料管理是什么?物料管理的具体工作有哪些?
大数据·前端·数据库·人工智能·精益工程
xixixi777771 天前
全模态原生大脑降临:GPT-5.5(Spud)发布,推理/编码提升30%,百万上下文+原生电脑控制,开启Agent新纪元
大数据·网络·人工智能·gpt·安全·电脑·量子计算