window+trigger+watermark处理全局乱序数据,指定窗口上的allowedLateness可以处理特定窗口操作的局部事件时间乱序数据

1、流处理系统中的微批

Flink内部也使用了某种形式的微批处理技术,在shuffle阶段将含有多个事件的缓冲容器通过网络发送,而不是发送单个事件
流处理系统中的批处理必须满足以下两点要求:

  • 批处理只作为提高系统性能的机制。批量越大,系统的吞吐量就越大。
  • 为了提高性能而使用的批处理必须完全独立于定义窗口时所用的缓冲,或者为了保证容错性而提交的代码,也不能作为 API 的一部分。否则,系统将受到限制,并且变得脆弱且难以使用。

2、时间概念

  • 事件时间,即事件实际发生的时间(由水印触发器实现),基于事件时间处理可实现时间回溯并正确地重新处理数据
  • 处理时间,即事件被处理的时间,是处理事件的机器所测量的时间
  • 摄取时间,即事件进入流处理框架的时间,缺乏事件时间的数据会被处理器附上摄取时间(由source函数完成)

3、窗口

所有内置窗口都由同一种机制实现,开窗机制与检查点机制完全分离;可直接用基本的开窗机制定义更复杂的窗口(如某种时间窗口,可基于元素计数生成中间结果)
窗口时间区间是按自然时间分配的,比如3秒的时间间隔,[0,3) [3,6)
(1)时间窗口(每隔B时长对A时长内数据聚合)

  • 设置事件时间 env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
  • 设置处理时间 env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime)
  • 设置摄取时间 env.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime)
  • 滚动窗口A stream.timeWindow(Time.minutes(1)) stream.window(TumblingEventTimeWindows.of(Time.seconds(1)))
  • 滑动窗口B stream.timeWindow(Time.minutes(1), Time.seconds(30)) stream.window(TumblingEventTimeWindows.of(Time.seconds(1)), SlidingEventTimeWindows.of(Time.seconds(30)))

(2)计数窗口(每隔B个元素对A个元素进行聚合)
为避免永远达不到计数窗口而浪费内存,可用时间窗口触发超时

  • 滚动窗口A stream.countWindow(4)
  • 滑动窗口B stream.countWindow(4, 2)

(3)会话窗口(会话即活动阶段,其前后都是非活跃阶段,常用于无固定持续时间或无固定交互次数的场景)
由超时时间设定,即希望非活跃状态持续多久才结束窗口。window区间:当b比上一条记录a延迟超过超时时间t时,出现会话窗口[上一个window_end, b-t)

  • 事件时间会话窗口 stream.window(EventTimeSessionWindows.withGap(Time.minutes(5))
  • 处理时间会话窗口 stream.window(ProcessingTimeSessionWindows.withGap(Time.minutes(5))

处理延迟数据

  • allowedLateness(Time.minutes(60))

缩短反馈时间(若用户会话迟迟不结束,反馈时间过长)

  • trigger(ContinuousEventTrigger.of(Time.minutes(10)) #每10分钟输出一个结果并覆盖之前的

(4)全局窗口(对全部数据进行统计,使用流方法实现批处理)
内置触发器是NeverTrigger,永远不会触发,需要自定义触发器才有意义
stream.window(GlobalWindows.create()).trigger(...)

4、触发器

继承Trigger类,Trigger抽象类的结构:

boolean canMerge()
void clear(W window, TriggerContext ctx)
TriggerResult onElement(T element, long timestamp, W window, TriggerContext ctx) 每个元素到来时执行
TriggerResult onEventTime(long time, W window, TriggerContext ctx) Timer到期后执行
void onMerge(W window, OnMergeContext ctx)
TriggerResult onProcessingTime(long time, W window, TriggerContext ctx)

5、水印

窗口 + 水印,用于解决乱序问题(并不是解决,而是假定所有正常的事件都只是一定程度内乱序,可以解决此程度内的乱序)

当Watermark在红色区域时,窗口内的元素会计算

(1)基于事件时间处理时,水印是判断所有事件到达的标志,开始计算和输出结果,晚于处理时间但早于此水印时间的事件也可被正确处理。
水印定义最长迟到数据(比当前watermark还早的数据会被丢弃,水印阈值越大,允许的迟到数据越久)
watermark的值不是全局的,但与key无关,有几个并行,就有几个watermark,window的触发条件与最小的watermark有关
水印时间 = 收到的最大事件时间 - 水印阈值

一个操作算子收到多个并行流的输入时,取最小的watermark作为当前算子的watermark

(2)异常情况:如果水印迟到得太久(可能是maxOrderness设置太大,也可能是后序事件过晚到达),收到结果的速度会变慢,解决方法是在水印到达之前输出近似结果,其实就是后面设置Lateness的方案;如果水印到达得太早(可能是maxOrderness设置太小,也可能是后序事件过早到达),则可能丢失一些前序事件,收到错误结果,解决方法是采用Flink作业监控事件流,学习事件的迟到规律,以此构建水印模型
(3)分配Timestamp和Watermark
timestamp和watermark都是通过从1970年1月1日0时0分0秒到现在的毫秒数来指定的
先后顺序:分配timstamp是按设置的时间间隔定时执行的,即使无数据进来也会执行,这就造成了getCurrentWatermark调用后看上去第一个watermark永远是以0为基准计算显示的 ,但实际并不是按那个算的。第2条的watermark如果是23的话,是不大于window_end 24的,也就不应该触发,而如果是下一条的24则可以触发。AssignerWithPeriodicWatermarks子类是每隔一段时间执行的,这个具体由ExecutionConfig.setAutoWatermarkInterval设置,如果没有设置会几乎没有间隔地调用getCurrentWatermark方法。之所以会出现-10000时因为你没有数据进入窗口,当然一直都是-10000,但是getCurrentWatermark方法不是在执行extractTimestamp后才执行的

直接在数据源生成(推荐,数据生成时即分配timestamp和watermark)
实现SourceFuntion接口的run方法,并调用如下方法:

  • 分配timestamp:SourceContext.collectWithTimestamp(...)
  • 分配watermark:SourceContext.emitWatermark(new WaterMark(...))

获取流后使用生成器生成新流(使用此种方式,会覆盖源提供的timestamp和watermark,注意一定要在时间窗口之前生成)
stram.assignTimestampsAndWatermarks( AssignerWithPeriodicWatermarks/AssignerWithPunctuatedWatermarks 实现类对象)
定义分配器
AssignerWithPeriodicWatermarks(周期性水印,分配时间戳并定期生成水印)
watermark产生的事件间隔(每n毫秒)是通过ExecutionConfig.setAutoWatermarkInterval(...)来定义的,当getCurrentWatermark()被调用时,若返回的watermark非空且大于上一个watermark,则发射一个新的watermark

  • 预定义实现类(使用时重写extractTimestamp):
    • AscendingTimestampExtractor 适用于时间戳递增的情况
    • BoundedOutOfOrdernessTimestampExtractor 适用于乱序但最大延迟已知的情况
  • 自定义实现类(使用时重写getCurrentWatermark、extractTimestamp)

AssignerWithPunctuatedWatermarks(带断点水印)
事件驱动生成水印,每个单独的event都可以产生一个watermark,会有额外计算,过多可能导致性能降低。任何一个event都触发extractTimestamp(...)来为元素分配一个timestamp,然后立即调用该元素上的checkAndGetNextWatermark(...)方法,一旦checkAndGetNextWatermark(...)返回一个非空的watermark并且watermark比前一个watermark大的话,这个新的watermark将会被发送
(4)设定水印后触发window的条件:

  • watermark >= window_end(开启多并发后,每个算子接收到的watermark都会进行对齐,取最小的watermark作为最终的watermark并往下一个算子发送)
  • 在[window_begin, window_end)中有数据存在

(5)不足之处
无法应对迟到数据,如果一个窗口已经被触发了,即使满足上述条件也不会第二次触发窗口。水印被发射到下一个算子前已默认比水印更早的数据已经全部处理了

6、allowedLateness

主要用于解决迟到问题,给迟到数据第二次或多次触发window的机会,可对无法触发window的迟到数据单独处理
默认情况下,watermark超过end-of-window后,将忽略之后到达的符合window的数据
在Watermark < 窗口结束时间 + Lateness时,仍会继续等待窗口内的元素参与窗口计算,计算时要注意状态值的重复,直到Watermark >= 窗口结束时间 + Lateness 时清空缓存
要注意再次触发窗口时,UDF中的状态值的处理,要考虑state在计算时的去重问题
(1)

  • 对于trigger是默认的EventTimeTrigger的情况,allowedLateness会再次触发窗口的计算,而之前触发的数据,会buffer起来,直到watermark超过end-of-window + allowedLateness的时间,窗口的数据及元数据信息才会被删除。再次计算就是DataFlow模型中的Accumulating的情况。
  • 对于sessionWindow情况,当late element在allowedLateness范围之内到达时,可能会引起窗口的merge,这样,之前窗口的数据会在新窗口中累加计算,这就是DataFlow模型中的AccumulatingAndRetracting的情况。

(2)触发条件

  • watermark < window_end + allowedLateness
  • 在[window_begin, window_end)中有late数据存在

7、定时器Timer

Flink Streaming API提供的用于感知并利用处理时间/事件时间变化的机制
(1)在KeyedProcessFunction实现类里定义定时器为例:
重写processElement(),对每个输入元素注册定时器
重写onTimer(),定时器触发时执行的逻辑
根据时间特征的不同,具体如下:
处理时间——调用Context.timerService().registerProcessingTimeTimer()注册;onTimer()在系统时间戳达到Timer设定的时间戳时触发。
事件时间——调用Context.timerService().registerEventTimeTimer()注册;onTimer()在Flink内部水印达到或超过Timer设定的时间戳时触发。
(2)EventTimeTrigger使用Timer实现触发时间窗口

@Override
public TriggerResult onElement(Object element, long timestamp, TimeWindow window, TriggerContext ctx) throws Exception {
if (window.maxTimestamp() <= ctx.getCurrentWatermark()) { return TriggerResult.FIRE; }
else { ctx.registerEventTimeTimer(window.maxTimestamp()); return TriggerResult.CONTINUE; }
}

  

Flink之对时间的处理的更多相关文章

  1. Flink学习(二)Flink中的时间

    摘自Apache Flink官网 最早的streaming 架构是storm的lambda架构 分为三个layer batch layer serving layer speed layer 一.在s ...

  2. 「Flink」Flink中的时间类型

    Flink中的时间类型和窗口是非常重要概念,是学习Flink必须要掌握的两个知识点. Flink中的时间类型 时间类型介绍 Flink流式处理中支持不同类型的时间.分为以下几种: 处理时间 Flink ...

  3. Flink基础:时间和水印

    ​ 往期推荐: Flink基础:入门介绍 Flink基础:DataStream API Flink基础:实时处理管道与ETL Flink深入浅出:资源管理 Flink深入浅出:部署模式 Flink深入 ...

  4. 第08讲:Flink 窗口、时间和水印

    Flink系列文章 第01讲:Flink 的应用场景和架构模型 第02讲:Flink 入门程序 WordCount 和 SQL 实现 第03讲:Flink 的编程模型与其他框架比较 第04讲:Flin ...

  5. 「Flink」事件时间与水印

    我们先来以滚动时间窗口为例,来看一下窗口的几个时间参数与Flink流处理系统时间特性的关系. 获取窗口开始时间Flink源代码 获取窗口的开始时间为以下代码: org.apache.flink.str ...

  6. Flink流处理的时间窗口

    Flink流处理的时间窗口 对于流处理系统来说,流入的消息是无限的,所以对于聚合或是连接等操作,流处理系统需要对流入的消息进行分段,然后基于每一段数据进行聚合或是连接等操作. 消息的分段即称为窗口,流 ...

  7. Flink Streaming基于滚动窗口的事件时间分析

    使用flink-1.9.0进行的测试,在不同的并行度下,Flink对事件时间的处理逻辑不同.包括1.1在并行度为1的本地模式分析和1.2在多并行度的本地模式分析两部分.通过理论结合源码进行验证,得到具 ...

  8. Flink的时间类型和watermark机制

    一FlinkTime类型 有3类时间,分别是数据本身的产生时间.进入Flink系统的时间和被处理的时间,在Flink系统中的数据可以有三种时间属性: Event Time 是每条数据在其生产设备上发生 ...

  9. Flink架构(三)- 事件-时间(Event-Time)处理

    3. 事件-时间(Event-Time)处理 在“时间语义”中,我们强调了在流处理应用中时间语义的重要性,并解释了处理时间与事件时间的不同点.处理时间较好理解,因为它基于本地机器的时间,它产生的是有点 ...

随机推荐

  1. 10 种常用 Matplotlib 图的 Python 代码

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 喜欢的朋友欢迎关注小编,除了分享技术文章之外还有很多福利,私信“资料”可以 ...

  2. cb45a_c++_STL_算法_删除_(3)_unique(唯一的意思)删除连续性的重复的数据

    cb45a_c++_STL_算法_删除_(3)_unique(唯一的意思)删除连续性的重复的数据unique(b,e),删除连续性的,删除重复的数据,比如如果有两个连续的5,5,则留下一个.uniqu ...

  3. 安卓开发-Activity-多个Activity的开发方法。

    原文链接:https://blog.csdn.net/weixin_38420342/article/details/84344496 一.切换Activity的5种方式 Intent intent ...

  4. 解决React Native安装应用到真机(红米3S)报Execution failed for task ':app:installDebug'的错误

    报错信息如下: :app:installDebug Installing APK 'app-debug.apk' on 'Redmi 3S - 6.0.1'Unable to install D:\R ...

  5. Mysql和Redis数据同步策略

    为什么对缓存只删除不更新 不更新缓存是防止并发更新导致的数据不一致. 所以为了降低数据不一致的概率,不应该更新缓存,而是直接将其删除, 然后等待下次发生cache miss时再把数据库中的数据同步到缓 ...

  6. SpringMVC 学习笔记(7)异常操作

    如何使用HandleException 在程序中,异常是最常见的,我们需要捕捉异常并处理它,才能保证程序不被终止. 最常见的异常处理方法就是用try catch来捕捉异常.这次我们使用springmv ...

  7. RabbitMQ:三、进阶

    保证消息的安全 持久化 交换器持久化:声明交换器时指定持久化 队列持久化:声明队列时指定持久化 消息持久化:发送消息时指定持久化 一般队列和消息持久化要同时声明,此外消息假如进了交换器却找不到队列,也 ...

  8. VM363:1 Uncaught SyntaxError: Invalid or unexpected token

    此报错主要是因为json字符串转json对象时,json字符串中出现特殊字符(如:换行符)报错. json字符转json对象(如下写则报错) 更改后 参考地址: https://www.cnblogs ...

  9. Spring IoC component-scan 节点详解

    前言 我们在了解 Spring 容器的扩展功能 (ApplicationContext) 之前,先介绍下 context:component-scan 标签的解析过程,其作用很大是注解能生效的关键所在 ...

  10. web如何测试

    当我们负责web测试的时候,先了解B/S架构,然后分析如何开始执行测试,一般步骤:从功能测试,兼容测试,安全测试. 功能测试: 一.链接测试,链接是web应用系统的一个很重要的特征,主要是用于页面之间 ...