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. fiddler修改请求参数

    1.打开fiddler ,点击界面左侧左侧底部 2.此图标为before request请求(修改请求参数时,设置这个,可以修改请求参数) 3..再次点击该按钮,将图标切换到下图after respo ...

  2. GestureDetector手势检测

    Android手势检测器GestureDetector,要创建一个GestureDetector需要传入一个监听器GestureDetector.OnGestureListener. 案例(实现手机相 ...

  3. 记PHP下载大文件失败的一次坑

    说明 php提供文件的储存和下载,nginx作为web服务器,fpm做解析. 现象 当下载一个5M大小的图片时,总提示下载失败,或下载下来的文件不完整,仅显示部分图像(每次下载不一样) php下载相关 ...

  4. Shell脚本 概括

    Shell脚本的管理 shell 脚本是linux命令的集合 介于操作系统内核与用户之间,赋值解释命令行 Shell的作用及常见种类 登录Shell 指用户每次登录系统后自动加载的Shell程序,大多 ...

  5. PHP丨PHP基础知识之数据类型

    PHP的数据类型主要有三大种:(细分的话8小种) 一.标量数据类型 标量数据类型包括以下几种: (1)BOOLEAN:布尔型 布尔变量是PHP变量中最简单的: 它保存一个TRUE或者FALSE值: 其 ...

  6. logback.xml 不能被加载,logback不能被执行,logback.xml 无法生效,slf4j日志样式输出失败

    1. 原因 logback.xml 无法被加载, 尝试了好久还是失败,哎,最后新建工程竟然可以,所以说还是项目的问题: 原来项目依赖了两个slf4j.jar,是版本冲突了: 2. 查找原因 idea ...

  7. 使用JUnit 和Jacoco进行单元测试

    Jacoco配置 <dependency> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven ...

  8. Redis设置并查看最大连接数

    在 Redis2.4 中,最大连接数是被直接硬编码在代码里面的,而在2.6版本中这个值变成可配置的. maxclients 的默认值是 10000,你也可以在 redis.conf 中对这个值进行修改 ...

  9. trollcave解题

    这是第一次完整地进行模拟渗透,前前后后一共花了一天时间,花了点时间写了个writeup. 博主是个菜鸡,如果有大神看到,请轻喷...... writeup下载:https://hrbeueducn-m ...

  10. ora-06502 ORA-06512问题解决

    Plsql报错:ORA-06502:PL/SQL:数字或值错误:字符串缓冲区太小  ORA-06512:等 这里网上常见解决方案是加大变量长度,但是我发现加大长度也没什么用,实际问题出在变量赋值上 例 ...