6、Time & Window
一、Time & Watermark
1.1、DataStream支持的三种time
- DataStream 有大量基于 time 的operator
- Flink支持三种 time:
- EventTime
- IngestTime
- ProcessingTime
三个时间的比较
- EventTime
- 事件生成时的时间,在进入 Flink 之前就已经存在,可以从 event 的字段中抽取
- 必须指定 watermarks 的生成方式
- 优势:确定性,乱序、延时、或者数据重复等情况,都能给出正确的结果
- 弱点:处理无序事件时性能和延迟受到影响
- IngestTime
- 事件进入flink的时间,即在 source 里获取的当前系统的时间,后续操作统一使用该时间
- 不需要指定 watermarks 的生成方式(自动生成)
- 弱点:不能处理无序事件和延迟数据
- ProcessingTime
- 执行操作的机器的当前系统时间(每个算子都不一样)
- 不需要流和机器之间的协调
- 优势:最佳的性能和最低的延迟
- 弱点:不确定性 ,容易受到各种因素影像(event产生的速度、到达flink的速度、在算子之间传输速度等),压根就不管顺序和延迟
- 比较
- 性能: ProcessingTime> IngestTime> EventTime
- 延迟: ProcessingTime< IngestTime< EventTime
- 确定性: EventTime> IngestTime> ProcessingTim
设置Time的类型
val env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime);
不设置Time 类型时,默认就是processingTime
1.2、Watermarks
实时系统中,由于各种原因造成的延时,造成某些消息发到 flink 的时间延时于事件产生的时间。如果基于 event time 构建 window,但是对于 late element,我们又不能无限期的等下去,必须要有个机制来保证一个特定的时间后,必须触发 window 去进行计算了。这个特别的机制,就是 watermark 。
在上面的时间类型中我们知道,Flink 中的时间:
- EventTime 每条数据都携带时间戳;
- ProcessingTime 数据不携带任何时间戳的信息;
- IngestionTime 和 EventTime 类似,不同的是 Flink 会使用系统时间作为时间戳绑定到每条数据,可以防止 Flink 内部处理数据是发生乱序的情况,但无法解决数据到达 Flink 之前发生的乱序问题。
- 所以,我们在处理消息乱序的情况时,会用 EventTime 和 WaterMark 进行配合使用。
水印的出现是为了解决实时计算中的数据乱序问题,它的本质是 DataStream 中一个带有时间戳的元素。如果 Flink 系统中出现了一个 WaterMark T,那么就意味着 EventTime < T 的数据都已经到达,窗口的结束时间和 T 相同的那个窗口被触发进行计算了。
也就是说:水印是 Flink 判断迟到数据的标准,同时也是窗口触发的标记。
在程序并行度大于 1 的情况下,会有多个流产生水印和窗口,这时候 Flink 会选取时间戳最小的水印。
我们可以考虑一个这样的例子:某 App 会记录用户的所有点击行为,并回传日志(在网络不好的情况下,先保存在本地,延后回传)。A 用户在 11:02 对 App 进行操作,B 用户在 11:03 操作了 App,但是 A 用户的网络不太稳定,回传日志延迟了,导致我们在服务端先接受到 B 用户 11:03 的消息,然后再接受到 A 用户 11:02 的消息,消息乱序了。那我们怎么保证基于 event-time 的窗口在销毁的时候,已经处理完了所有的数据呢?这就是 watermark 的功能所在。watermark 会携带一个单调递增的时间戳 t,watermark(t) 表示所有时间戳不大于 t 的数据都已经到来了,未来不会再来,因此可以放心的触发和销毁窗口了。
有序流中Watermarks
- 在某些情况下,基于Event Time的数据流是有续的
- 在有序流中,watermark就是一个简单的周期性标记。
乱序流中Watermarks
- 在更多场景下,基于Event Time的数据流是无续的
- 在无序流中,watermark至关重要,它告诉 operator 比 watermark 更早(更老/时间戳更小)的事件已经到达, operator 可以将内部事件时间提前到 watermark 的时间戳(可以触发window计算)
并行流中的Watermarks
- 通常情况下, watermark在source函数中生成,但是也可以在source后任何阶段,如果指定多次后面会覆盖前面的值。 source的每个sub task独立生成水印
- watermark通过operator时会推进operators处的当前event time,同时operators会为下游生成一个新的watermark
- 多输入operator(union、 keyBy)的当前event time是其输入流event time的最小值
迟到的数据
上面的 watermark 让我们能够应对乱序的数据,但是真实世界中我们没法得到一个完美的 watermark 数值,要么没法获取到,要么耗费太大,因此实际工作中我们会使用近似 watermark,生成 watermark(t) 之后,还有较小的概率接受到时间戳 t 之前的数据,在 Flink 中将这些数据定义为 “late elements”, 同样我们可以在 window 中指定是允许延迟的最大时间(默认为 0),可以使用下面的代码进行设置:
设置 `allowedLateness` 之后,迟来的数据同样可以触发窗口,进行输出,利用 Flink的 side output 机制,我们可以获取到这些迟到的数据,使用方式如下:
需要注意的是,设置了 allowedLateness 之后,迟到的数据也可能触发窗口,对于Session window 来说,可能会对窗口进行合并,产生预期外的行为。
二、Window
什么是windows,以及windows的作用
- Flink 认为 Batch 是 Streaming 的一个特例,所以 Flink 底层引擎是一个流式引擎,在上面实现了流 处理和批处理。而窗口(window)就是从 Streaming 到 Batch 的一个桥 梁。Flink 提供了非常完善 的窗口机制,这是Flink 最大的亮点之一(其他的亮点包括消息乱序处理,和 checkpoint 机制)。
- Window是一种切割无限数据集为有限块并进行相应计算的处理手段(跟keyBy一样,也是一种分组手段,只不过同一event可能被分到多个组)
- 在流处理应用中,数据是连续不断的,因此我们不可能等到所有数据都到了才开始处理。当然我们 可以每来一个消息就处理一次,但是有时我们需要做一些聚合类的处 理,例如:在过去的1分钟内 有多少用户点击了我们的网页。在这种情况下,我们必须定义一个窗口,用来收集最近一分钟内的 数据,并对这个窗口内的数据进行计算。
Window分类,分为Keyed Windows和Non-Keyed Windows,取决于是否使用了keyBy
- Keyed Windows(在已经按照key分组的基础上(KeyedStream),再构建多任务并行window)
- Non-Keyed Windows(在未分组的DataStream上构建单任务window,并行度是1,API都带All后缀)
WindowedStream & AllWindowedStream
- WindowedStream代表了根据key分组,并且基于WindowAssigner切分窗口的数据流。所以WindowedStream都是从KeyedStream衍生而来的。而在WindowedStream上 进行任何transformation也都将转变回DataStream。
val stream: DataStream[MyType] = ...
val windowed: WindowedDataStream[MyType] = stream
.keyBy("userId")
.window(TumblingEventTimeWindows.of(Time.seconds(5))) // Last 5 seconds of data 5 秒计算一次
val result: DataStream[ResultType] = windowed.reduce(myReducer)
- 上述 WindowedStream 的样例代码在运行时会转换成如下的执行图:
- Flink 的窗口实现中会将到达的数据缓存在对应的窗口buffer中。当到达窗口发送的条件时,Flink 会对整个窗口中的数据进行处理(由Trigger控制)。Flink 在聚合类窗口 有一定的优化,即不会保存窗口中的所有值,而是每到一个元素执行一次聚合函数,最终只保存一份数据即可。
- 在key分组的流上进行窗口切分是比较常用的场景,也能够很好地并行化(不同的key上的窗口聚合可以分配到不同的task去处理)。不过有时候我们也需要在普通流上进 行窗口的操作,这就是 AllWindowedStream。AllWindowedStream是直接在DataStream上进行windowAll(...)操作。AllWindowedStream 的实现是基于 WindowedStream 的(Flink 1.1.x 开始)。Flink 不推荐使用AllWindowedStream,因为在普通流上进行窗口操作,就势必需要将所有分区的流都汇集到单个的Task中, 而这个单个的Task很显然就会成为整个Job的瓶颈。
Keyed Windows 对比 Non-Keyed Windows(以基于time的window为例)
Window的生命周期
- 创建:当属于该窗口的第一个元素到达时就会创建该窗口
- 销毁:当时间(event/process time)超过窗口的结束时间戳+用户指定的延迟时
- (allowedLateness()),窗口将被移除(仅限time-based window)
- 例如:对于一个每5分钟创建Tumbling Windows(即翻滚窗口)窗口,允许1分钟的时延,Flink将会在12:00到12:05这段时间内第一个元素到达时创建窗口,当 watermark超过12:06时,该窗口将被移除
- Trigger(触发器):指定了窗口函数在什么条件下可被触发,触发器还可以决定在创建和删除窗口之间的任何时间清除窗口的内容。在这种情况下,清除仅限于窗口中的元 素,而不是窗口元数据。这意味着新数据仍然可以添加到该窗口中。
- 例如:当窗口中的元素个数超过4个时“ 或者 ”当水印达到窗口的边界时“触发计算
- Evictor(驱逐者):将在触发器触发之后或者在函数被应用前后,清除窗口中的元素
- Window 的函数:函数里定义了应用于窗口(Window)内容的计算逻辑
窗口分配器(Window Assingers)
- Window Assinger是干啥的
- 当你决定stream是否keyby之后,window是没有构建的,你还需要指定一个window Assinger 用于定义元素如何分配到窗口中
- window Assinger如何指定?
- Keyedstream:window(WindowAssigner)
- non-keyed streams:windowAll(WindowAssigner)
- window Assinger的作用:负责将每个传入的元素分配给一个或多个窗口
Window分类(Window Assinger类型)
- 有了window Assinger,才会创建出各种形式的window来覆盖我们所需的各种场景,所以不用 过多关注window本身的分类,关注window Assinger的分类即可
- Count-based window:根据元素个数对数据流进行分组切片
- Tumbling CountWindow
- Sliding CountWindow
- Time-based window :根据时间对数据流进行分组切片,设置方式window(start,end)
- Tumbling Window
- Sliding Window
- Session Window
Tumbling Windows(翻滚窗口)
- 定义:将数据依据固定的窗口长度对数据进行切片
- 特点:
- 时间对齐
- 窗口长度固定
- event无重叠
- 适用场景:计算各个时间段的指标
Tumbling Windows的使用
- 对齐方式:默认是aligned with epoch(整点、整分、整秒等),可以通过offset参数改变对齐方式
Sliding Windows(滑动窗口)
- 定义:是固定窗口的更广义的一种形式。滑动窗口由固定的窗口长度和滑动间隔组成
- 特点:
- 时间对齐
- 窗口长度固定
- event有重叠
- 适用场景:每5分钟求统计一小时的数据
Sliding Windows的使用
对齐方式:默认是aligned with epoch(整点、整分、整秒等),可以通过offset参数改变对齐方式
Session Windows(事件窗口)
- 定义:类似于web应用 的session,即一段时间没有接受到新数据就会生成新的窗口(固定gap/gap fun)
- 特点:
- 时间无对齐
- event不重叠
- 没有固定开始和结束时间
- 适用场景:基于用户行为进行统计分析
Session Windows的使用
- Gap
- 固定gap
- 动态gap:实现SessionWindowTimeGapExtractor
- 特殊处理方式
- session window operator为每个到达的event创建一个新窗口,如果它们之间的距离比定义的间隔更近,则将窗口合并在一起
- 为了能够合并, session window operator需要合并触发器和合并窗口函数,例如ReduceFunction、 AggregateFunction或ProcessWindowFunction (FoldFunction 不能合并)
Global Windows
- 定义:有相同key的所有元素分配给相同的单个全局窗口
- 必须指定自定义触发器否则没有任何意义
- 注意:不要跟Non-keyed Window搞混,两个不同的角度
6、Time & Window的更多相关文章
- JS跨域:jsonp、跨域资源共享、iframe+window.name
JS跨域:jsonp.跨域资源共享.iframe+window.name :https://www.cnblogs.com/doudoublog/p/8652213.html JS中的跨域 请求跨域有 ...
- [转载]ExtJs4 笔记(9) Ext.Panel 面板控件、 Ext.window.Window 窗口控件、 Ext.container.Viewport 布局控件
作者:李盼(Lipan)出处:[Lipan] (http://www.cnblogs.com/lipan/)版权声明:本文的版权归作者与博客园共有.转载时须注明本文的详细链接,否则作者将保留追究其法律 ...
- ExtJs4 笔记(9) Ext.Panel 面板控件、 Ext.window.Window 窗口控件、 Ext.container.Viewport 布局控件
本篇讲解三个容器类控件. 一.面板控件 Ext.Panel 一个面板控件包括几个部分,有标题栏.工具栏.正文.按钮区.标题栏位于最上面,工具栏可以在四个位置放置,围绕中间部分正文,按钮区位于最小方.下 ...
- TCP系列43—拥塞控制—6、Congestion Window Validation(CWV)
一.概述 在RFC2861中,区分了TCP连接数据传输的三种状态 After sending a data segment: If tcpnow - T_last >= RTO ...
- TCP系列33—窗口管理&流控—7、Silly Window Syndrome(SWS)
一.SWS介绍 前面我们已经通过示例看到如果接收端的应用层一直没有读取数据,那么window size就会慢慢变小最终可能变为0,此时我们假设一种场景,如果应用层读取少量数据(比如十几bytes),接 ...
- Linux系列:进阶之jdk、X window安装与使用
1.安装x window 分为两步: 1.安装 x window,执行指令yum groupinstall “X Window” 2.安装GNOME Desktop,执行指令yum groupinst ...
- How To mount/Browse Windows Shares【在linux{centos}上挂载、浏览window共享】
How to mount remote Windows shares Contents Required packages Basic method Better Method Even-better ...
- 批处理 安装、卸载 window service
注意:安装中调用了卸载的bat,安装之前先卸载...PS:可以删除 安装代码: @echo off set filename=LXServer.exe set servicename=Service1 ...
- 深入理解,函数声明、函数表达式、匿名函数、立即执行函数、window.onload的区别.
一.函数声明.函数表达式.匿名函数1.函数声明:function fnName () {…};使用function关键字声明一个函数,再指定一个函数名,叫函数声明. 2.函数表达式 var fnNam ...
随机推荐
- 图的广度优先遍历(bfs)
广度优先遍历: 1.将起点s 放入队列Q(访问) 2.只要Q不为空,就循环执行下列处理 (1)从Q取出顶点u 进行访问(访问结束) (2)将与u 相邻的未访问顶点v 放入Q, 同时将d[v]更新为d[ ...
- PyCharm3.0 快捷键
1.编辑(Editing) Ctrl + Space 基本的代码完成(类.方法.属性)Ctrl + Alt + Space 快速导入任意类Ctrl + Shift + Enter 语句完 ...
- python 开发工具简介
一.python 开发工具简介 1.IDLE IDLE是开发python程序的基本IDE(集成开发环境),具备基本的IDE的功能,是非商业Python开发的不错的选择.当安装好python以后,IDL ...
- 白话web安全
伤心往事 梦回大二,那时候沉迷于毒奶粉,甚至国庆都在宿舍与毒奶粉共同度过,但是却发生了一件让我迄今难忘的事情~ 我新练的黑暗武士被盗了!!!干干净净!!! 虽然过了好久了,但是记忆犹新啊,仿佛发生在昨 ...
- Aircoinst 三层架构ASP.NET开源
<注意! 本源码为我本人所写,可能有点烂.仅供学习使用,请勿进行商业用途~!> <本源码永久归于MineLSG 及 Aircoinst_慈 所拥有> 使用方法:直接拷贝 一.结 ...
- 感染(low)bfs 、感染(mid) 二分、感染(high) 二分 + 维护单调 队列去除无用的点
感染(low) Description n户人家住在一条直线上,从左往右依次编号为1,2,-,n.起初,有m户人家感染了COVID-19,而接下来的每天感染的人家都会感染他家左右两家的人,问t天后总共 ...
- 让你第一次认识到Java的内存管理
发现之前写的可读性不好,这次准备试试换风格,去掉长篇大论,觉得这个风格好的,麻烦点个赞啦 清理.JVM的妙处 大家以后都是程序员,假设你很不幸,需要自己交钱租房子. 你作为一个小穷人,租的房子到期了( ...
- Spring之Bean的管理方式(Content,Beans)
Spring的bean管理(注释) 注解 代码里特殊的标记,使用注解也可以直接完成相关功能 注解写法:@注解名称(属性名=属性值) 使用在类,方法,属性上面 Spring注解开发准备 导入jar包 ( ...
- Java toString解析
Java toString解析 我们知道,Java所有的类都是Object类的派生类,toString就是Object类中的一个方法. 我们看看它的源代码. public String toStrin ...
- Jmeter 压力测试笔记(1)--服务器迁移失败
近期,公司服务器因技术架构升级等原因需要迁移,在经过开发,运维DBA,测试多部门进行联合讨论后,制定出了迁移方案.迁移前也对APP应用进行了各种测试,并没有发现问题. 凌晨2点开始迁移,5点完成迁移. ...