Flink流处理:高效应对迟到数据的三大策略

目录

代码功能总结

拓展理论

1. 事件时间与 Watermark

2. 迟到数据处理策略

3. 不同窗口类型对迟到数据的处理差异

4. 迟到数据处理的权衡

5. 其他相关概念


package window

import java.text.SimpleDateFormat
import java.time.Duration

import org.apache.flink.api.common.eventtime.{SerializableTimestampAssigner, WatermarkStrategy}
import org.apache.flink.api.common.functions.AggregateFunction
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.scala.function.ProcessWindowFunction
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.util.Collector

/**
 *
 * @PROJECT_NAME: flink1.13
 * @PACKAGE_NAME: window
 * @author: 赵嘉盟-HONOR
 * @data: 2023-05-23 19:51
 * @DESCRIPTION
 *
 */
object LateDataExample {
  def main(args: Array[String]): Unit = {
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    env.setParallelism(1)
    //TODO 处理迟到数据的三种方式
    //定义一个测输出流标签
    val outputTag=OutputTag[Event]("late-data")

    val data1 = env.socketTextStream("localhost", 7777)
      .map(data => {
        val datas = data.split(",")
        Event(datas(0).trim, datas(1).trim, datas(2).trim.toLong)
      })
    //TODO 一重保证:Watermark
    val result = data1.assignTimestampsAndWatermarks(WatermarkStrategy.forBoundedOutOfOrderness[Event](Duration.ofSeconds(5))
      .withTimestampAssigner(new SerializableTimestampAssigner[Event] {
        override def extractTimestamp(t: Event, l: Long): Long = t.timestamp
      })).keyBy(_.user).window(TumblingEventTimeWindows.of(Time.seconds(10)))
      //TODO 二重保证:指定窗口允许等待时间
      .allowedLateness(Time.minutes(1))
      //TODO 三重保证:将迟到数据输出到侧输出流
      .sideOutputLateData(outputTag)
      .aggregate(new AggregateFunction[Event, Long, Long] {
        override def createAccumulator(): Long = 0L
        override def add(in: Event, acc: Long): Long = acc + 1
        override def getResult(acc: Long): Long = acc
        override def merge(acc: Long, acc1: Long): Long = ???
      }, new ProcessWindowFunction[Long, UrlViewCount, String, TimeWindow] {
        override def process(key: String, context: Context, elements: Iterable[Long], out: Collector[UrlViewCount]): Unit = {
          out.collect(UrlViewCount(key,
            elements.iterator.next(),
            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(context.window.getStart),
            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(context.window.getEnd)
          ))
        }
      })

    result.print("result")
    data1.print("data ")
    result.getSideOutput(outputTag).print("late-data")
    env.execute("watermark")
  }

}

这段代码是一个使用 Apache Flink 处理流数据的示例,主要演示了如何处理迟到数据。下面我将总结代码功能并拓展相关理论。


代码功能总结

这段代码实现了一个基于事件时间的滚动窗口统计系统,主要功能包括:

  1. 数据源:从本地 socket 端口 7777 接收输入数据,数据格式为 user,url,timestamp

  2. 数据处理

    • 将输入的字符串解析为 Event 对象
    • 为数据流分配时间戳并生成 Watermark(允许 5 秒的乱序)
    • 按照用户进行分组,使用 10 秒的滚动事件时间窗口
  3. 迟到数据处理

    • 第一重保障:使用 Watermark 机制处理一定程度的乱序数据(5 秒)
    • 第二重保障:设置窗口允许等待时间为 1 分钟,即窗口关闭后仍会继续收集迟到数据并更新结果
    • 第三重保障:将超过允许等待时间的迟到数据输出到侧输出流
  4. 结果输出

    • 正常数据的统计结果输出到 "result"
    • 原始输入数据输出到 "data"
    • 迟到数据输出到 "late-data"

拓展理论

1. 事件时间与 Watermark

在流处理中,时间语义分为:

  • 处理时间:数据到达处理系统的时间
  • 摄入时间:数据进入 Flink 的时间
  • 事件时间:数据实际发生的时间

事件时间处理需要解决乱序数据问题,Watermark 是 Flink 中处理乱序数据的核心机制。它表示一个时间戳,即后续不会再出现早于该时间戳的数据。

2. 迟到数据处理策略

在实际生产环境中,迟到数据是不可避免的,Flink 提供了多种处理策略:

  1. Watermark 机制:设置合理的乱序容忍度,确保大部分迟到数据能被正确处理

  2. 窗口允许等待时间

    .allowedLateness(Time.minutes(1))
    
     

    窗口关闭后继续接收迟到数据并更新结果,适用于对结果准确性要求较高的场景

  3. 侧输出流

    .sideOutputLateData(outputTag)
    
     

    将无法处理的迟到数据单独输出,适用于需要保留所有数据记录的场景

  4. 状态清理策略

    .withEventTimeOutputWatermarks(
        WatermarkStrategy
            .<MyEvent>forBoundedOutOfOrderness(Duration.ofSeconds(20))
            .withIdleness(Duration.ofMinutes(1))
    )
    
     

    对于长时间空闲的流,可以配置 Watermark 生成器进入空闲状态,避免状态无限增长

3. 不同窗口类型对迟到数据的处理差异

不同窗口类型对迟到数据的处理方式有所不同:

  • 滚动窗口:迟到数据可能会触发窗口重新计算
  • 滑动窗口:迟到数据可能影响多个窗口的结果
  • 会话窗口:迟到数据可能会合并两个已关闭的会话窗口
4. 迟到数据处理的权衡

在实际应用中,需要根据业务需求权衡以下因素:

  • 结果准确性 vs 处理延迟:允许等待时间越长,结果越准确,但处理延迟也越大
  • 状态管理开销:窗口允许等待时间越长,Flink 需要维护的状态就越多
  • 下游系统影响:窗口结果的更新可能会对下游系统造成影响,需要考虑幂等性设计
5. 其他相关概念
  • 水印生成策略:除了固定延迟策略,Flink 还提供了升序时间戳、自定义水印生成器等策略
  • 触发器:控制窗口何时触发计算,可以自定义触发器实现更灵活的触发逻辑
  • 增量聚合:使用 AggregateFunction 可以在窗口内进行增量聚合,减少内存占用

以上是对这段代码的功能总结和相关理论的拓展。在实际生产环境中,需要根据业务场景选择合适的时间语义和迟到数据处理策略。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

渣渣盟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值