【大数据】Flink 架构(三):事件时间处理

Flink 架构》系列(已完结),共包含以下 6 篇文章:

  • Flink 架构(一):系统架构
  • Flink 架构(二):数据传输
  • Flink 架构(三):事件时间处理
  • Flink 架构(四):状态管理
  • Flink 架构(五):检查点 Checkpoint(看完即懂)
  • Flink 架构(六):保存点 Savepoint

😊 如果您觉得这篇文章有用 ✔️ 的话,请给博主一个一键三连 🚀🚀🚀 吧 (点赞 🧡、关注 💛、收藏 💚)!!!您的支持 💖💖💖 将激励 🔥 博主输出更多优质内容!!!

Flink 架构(三):事件时间处理

  • 1.时间戳
  • 2.水位线
  • 3.水位线传播和事件时间
  • 4.时间戳分配和水位线生成

在之前的博客中,我们强调了时间语义对于流处理应用的重要性并解释了 处理时间事件时间 的差异。虽然处理时间是基于处理机器的本地时间,相对容易理解,但它会产生一些较为随意、不一致且无法重现的结果。相反,事件时间语义会生成可重现且一致性的结果,这也是很多流处理用例的刚性需求。但和基于处理时间语义的应用相比,基于事件时间的应用需要一些额外的配置。此外,相比纯粹使用处理时间的引擎,支持事件时间的流处理引擎内部要更加复杂。

Flink 不仅针对常见的事件时间操作提供了直观易用的原语,还支持一些表达能力很强的 API,允许使用者以自定义算子的方式实现更高级的事件时间处理应用。在面对这些高级应用时,充分理解 Flink 内部事件处理机制通常会有所帮助,有时候更是必要的。在《流处理基础概念(二):时间语义(处理时间、事件时间、水位线)》一文中,我们介绍了 Flink 在提供处理时间语义时所采用的两个概念:记录时间戳水位线。接下面我们会介绍 Flink 内部如何实现和处理时间戳及水位线以支持事件时间语义的流式应用。

1.时间戳

在事件时间模式下,Flink 流式应用处理的所有记录都必须包含时间戳。时间戳将记录和特定时间点进行关联,这些时间点通常是记录所对应事件的发生时间。但实际上应用可以自由选择时间戳的含义,只要保证流记录的时间戳会随着数据流的前进大致递增即可。正如前文所述,基本上所有现实应用场景都会出现一定程度的时间戳乱序。

当 Flink 以事件时间模式处理数据流时,会根据记录的时间戳触发时间相关算子的计算。例如,时间窗口算子会根据记录关联的时间戳将其分配到窗口中。Flink 内部采用 8 字节的 Long 值对时间戳进行编码,并将它们以元数据(metadata)的形式附加在记录上。内置算子会将这个 Long 值解析为毫秒精度的 Unix 时间戳(自 1970-01-01-00:00:00.000 以来的毫秒数)。但自定义算子可以有自己的时间戳解析机制,如将精度调整为微秒。

2.水位线

除了记录的时间戳,Flink 基于事件时间的应用还必须提供 水位线watermark)。水位线用于在事件时间应用中推断每个任务当前的事件时间。基于时间的算子会使用这个时间来触发计算并推动进度前进。例如:基于时间窗口的任务会在其事件时间超过窗口结束边界时进行最终的窗口计算并发出结果。

当一个算子接收到时间为 T 的水位线,就可以认为不会再收到任何时间戳小于或等于 T 的事件了。水位线无论对于事件时间窗口还是处理乱序事件的算子都很关键。算子一旦收到某个水位线,就相当于接收到信号:某个特定时间区间的时间戳已经到齐,可以触发窗口计算或对接收的数据进行排序了
在这里插入图片描述
在 Flink 中,水位线是利用一些包含 Long 值时间戳的特殊记录来实现的。如上图所示,它们像带有额外时间戳的常规记录一样在数据流中移动。

水位线拥有两个基本属性:

  • 必须单调递增。这是为了确保任务中的事件时间时钟正确前进,不会倒退。
  • 和记录的时间戳存在联系。一个时间戳为 T 的水位线表示,接下来所有记录的时间戳一定都大于 T。

第二个属性可用来处理数据流中时间戳乱序的记录,例如上图中的时间戳为 3 和 5 的记录。对基于时间的算子任务而言,其收集和处理的记录可能会包含乱序的时间戳。这些算子只有当自己的事件时间时钟(由接收的水位线驱动)指示不必再等那些包含相关时间戳的记录时,才会最终触发计算。当任务收到一个违反水位线属性,即时间戳小于或等于前一个水位线的记录时,该记录本应参与的计算可能已经完成。我们称此类记录为 迟到记录late record)。为了处理迟到记录,Flink 提供了不同的机制,我们将在后续讨论它们。

水位线的意义之一在于它允许应用控制结果的完整性和延迟。如果水位线和记录的时间戳非常接近,那结果的处理延迟就会很低,因为任务无须等待过多记录就可以触发最终计算。但同时结果的完整性可能会受影响,因为可能有部分相关记录被视为迟到记录,没能参与运算。相反,非常 “保守” 的水位线会增加处理延迟,但同时结果的完整性也会有所提升。

3.水位线传播和事件时间

Flink 内部将水位线实现为特殊的记录,它们可以通过算子任务进行接收和发送。任务内部的 时间服务time service)会维护一些 计时器timer),它们依靠接收到水位线来激活。这些计时器是由任务在时间服务内注册,并在将来的某个时间点执行计算。例如:窗口算子会为每个活动窗口注册一个计时器,它们会在事件时间超过窗口的结束时间时清理窗口状态。

当任务接收到一个水位线时会执行以下操作:

  • 基于水位线记录的时间戳更新内部事件时间时钟。
  • 任务的时间服务会找出所有触发时间小于更新后事件时间的计时器。对于每个到期的计时器,调用回调函数,利用它来执行计算或发出记录。
  • 任务根据更新后的事件时间将水位线发出。

Flink 对通过 DataStream API 访问时间戳和水位线有一定限制。普通函数无法读写记录的时间戳或水位线,但一系列处理函数(process function)除外。它们可以读取当前正在处理记录的时间戳,获得当前算子的事件时间,还能注册计时器。所有函数的 API 都无法支持设置发出记录的时间戳、调整任务的事件时间时钟或发出水位线。为发出记录配置时间戳的工作需要由基于时间的 DataStream 算子任务来完成,这样才能确保时间戳和发出的水位线对齐。举例而言,时间窗口算子任务会在发送触发窗口计算的水位线时间戳之前,将所有经过窗口计算所得结果的时间戳设为窗口的结束时间。

接下来我们详细解释一下任务在收到一个新的水位线之后,将如何发送水位线和更新其内部事件时间时钟。Flink 会将数据流划分为不同的分区,并将它们交由不同的算子任务来并行执行。每个分区作为一个数据流,都会包含带有时间戳的记录以及水位线。根据算子的上下游连接情况,其任务可能需要同时接收来自多个输入分区的记录和水位线,也可能需要将它们发送到多个输出分区。下面我们将详细介绍一个任务如何将水位线发送至多个输出任务,以及它从多个输入任务获取水位线后如何推动事件时间时钟前进。

一个任务会为它的每个输入分区都维护一个 分区水位线partition watermark)。当收到某个分区传来的水位线后,任务会以接收值和当前值中较大的那个去更新对应分区水位线的值。随后,任务会把事件时间时钟调整为所有分区水位线中最小的那个值。如果事件时间时钟向前推动,任务会先处理因此而触发的所有计时器,之后才会把对应的水位线发往所有连接的输出分区,以实现事件时间到全部下游任务的广播。

下图展示了一个有 4 个输入分区和 3 个输出分区的任务在接收到水位线后,是如何更新它的分区水位线和事件时间时钟,并将水位线发出的。

在这里插入图片描述
对于那些有着两条或多条输入数据流的算子,如 UnionCoFlatMap,它们的任务同样是利用全部分区水位线中的最小值来计算事件时间时钟,并没有考虑分区是否来自不同的输入流。这就导致所有输入的记录都必须基于同一个事件时间时钟来处理。如果不同输入流的事件时间没有对齐,那么该行为就会导致一些问题。

Flink 的水位线处理和传播算法保证了算子任务所发出的记录时间戳和水位线一定会对齐。然而,这依赖于一个事实:所有分区都会持续提供自增的水位线。只要有一个分区的水位线没有前进,或分区完全空闲下来不再发送任何记录或水位线,任务的事件时间时钟就不会前进,继而导致计时器无法触发。这种情形会给那些靠时钟前进来执行计算或清除状态的时间相关算子带来麻烦。因此,如果一个任务没有从全部输入任务以常规间隔接收新的水位线,就会导致时间相关算子的处理延迟或状态大小激增。

当算子两个输入流的水位线差距很大时,也会产生类似影响。对于一个有两个输入流的任务而言,其事件时间时钟会受制于那个相对较慢的流,而较快流的记录或中间结果会在状态中缓冲,直到事件时间时钟到达允许处理它们的那个点。

4.时间戳分配和水位线生成

到目前为止,我们已经解释了时间戳和水位线的含义以及它们在 Flink 内部的处理逻辑,但一直没涉及它们的来源。时间戳和水位线通常都是在数据流刚刚进入流处理应用的时候分配和生成的。由于不同的应用会选择不同的时间戳,而水位线依赖于时间戳和数据流本身的特征,所以应用必须显式地分配时间戳和生成水位线。Flink DataStream 应用可以通过三种方式完成该工作:

  • 在数据源完成:我们可以利用 SourceFunction 在应用读入数据流的时候分配时间戳和生成水位线。源函数会发出一条记录流。每个发出的记录都可以附加一个时间戳,水位线可以作为特殊记录在任何时间点发出。如果源函数(临时性地)不再发出水位线,可以把自己声明成空闲。Flink 会在后续算子计算水位线的时候把那些来自于空闲源函数的流分区排除在外。数据源空闲声明机制 可以用来解决上面提到的水位线不向前推进的问题。我们会在后续详细讨论数据源函数。
  • 周期分配器periodic assigner):DataStream API 提供了一个名为 AssignerWithPeriodicWatermarks 的用户自定义函数,它可以用来从每条记录提取时间戳,并周期性地响应获取当前水位线的查询请求。提取出来的时间戳会附加到各自的记录上,查询得到的水位线会注入到数据流中。这个函数会在后续介绍。
  • 定点分配器punctuated assigner):另一个支持从记录中提取时间戳的用户自定义函数叫作 AssignerWithPunctuatedWatermarks。它可用于需要根据特殊输入记录生成水位线的情况。和 AssignerWithPeriodicWatermarks 函数不同,这个函数不会强制你从每条记录中都提取一个时间戳(虽然这样也行)。这个函数也会在后续介绍。

用户自定义的时间戳分配函数通常都会尽可能地靠近数据源算子,因为在经过其他算子处理后,记录顺序和它们的时间戳会变得难以推断。这也是为什么不建议在流式应用中途覆盖已有的时间戳和水位线(虽然这可以通过用户自定义函数实现)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/357233.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Python笔记-设计模式】建造者模式

一、说明 又称生成器,是一种创建型设计模式,使其能够分步骤创建复杂对象。允许使用相同的创建代码生成不同类型和形式的对象。 (一) 解决问题 对象的创建问题:当一个对象的构建过程复杂,且部分构建过程相互独立时,可…

吉利汽车:S-SDLC融入开发体系,推动智能汽车安全发展

吉利汽车是中国汽车行业的知名品牌,是一家具有国际化视野的汽车企业,在中国汽车市场自主品牌中占据领军地位。吉利汽车集团数字化中心利用数字化技术优势赋能业务升级,推动研发效率提升和产品安全能力拓展,进行整体数字化转型。 在…

键盘上Ins键的作用

前几天编写文档时,发现一个问题:插入内容时,输入的字符将会覆盖光标位置后的字符。原来是按到了键盘上的 Ins键,解决方法是:再按一次 Ins键(Ins键如果独立作为一键时,否则使用 “Fn Ins”组合键…

C++ —— 智能指针

C —— 智能指针 文章目录 C —— 智能指针一、为什么需要使用智能指针?二、内存泄漏什么是内存泄漏?内存泄漏的危害?内存泄漏分类 三、智能指针的使用及原理1. RAII2. 智能指针的原理 三、智能指针的缺陷及其发展3.1 std::auto_ptr3.2 std::…

华为笔记本matebook pro X如何扩容 C 盘空间

一、前提条件 磁盘扩展与合并必须是相邻分区空间,且两个磁盘类型需要相同。以磁盘分区为 C 盘和 D 盘为例,如果您希望增加 C 盘容量,可以先将 D 盘合并到 C 盘,然后重新创建磁盘分区,分配 C 盘和 D 盘的空间大小。 访…

Element ui 的组件弹窗 el-dialog点击的时候全屏变灰问题解决

最近在使用Element UI 的弹窗组件的时候发现这个组件各种的应用都没有问题,数据和元素的应用都是正确的但是在点击显示这个弹窗的时候全屏幕都会变灰。 这也不是因为增加了modal 遮挡幕的问题,在经过不断的排查代码的时候基本排除了代码的问题&#xf…

利用外卖系统源码构建高效的在线订餐平台

在当今数字化时代,外卖服务已成为人们日常生活中不可或缺的一部分。为了满足用户需求,许多创业者和企业都希望搭建自己的在线订餐平台。利用现有的外卖系统源码,可以快速构建一个高效、安全的在线订餐平台。本文将介绍如何利用外卖系统源码来…

Qt SQLite3数据库加密 QtCipherSqlitePlugin

在客户端软件开发过程中,基本都会涉及到数据库的开发。QT支持的数据库也有好几种(QSQLITE, QODBC, QODBC3, QPSQL, QPSQL7),SQLite就是其中之一,但这个 SQLite 是官方提供的开源版本,没有加密功能的。如果对…

k8s 进阶实战笔记 | 应用的蓝绿、金丝雀发布笔记

文章目录 应用的蓝绿、金丝雀发布笔记应用升级策略停机升级滚动更新蓝绿发布金丝雀发布 应用的蓝绿、金丝雀发布笔记 应用升级策略 Deployment.spec.strategy 设置 Recreate:同时删除所有副本,停机升级策略 不存在新老版本共存 存在某个时间段服务不可…

麒麟系统—— openKylin 安装 redis

麒麟系统—— openKylin 安装 redis 一、准备工作1. 确保麒麟系统 openKylin 已经安装完毕。 二、下载安装文件三、解压安装解压安装 四、配置与运行修改配置文件以配置文件运行 五、加入到服务中最终:介绍配置的其他参数使用 Redis是一种开源的、基于内存的高速缓存…

MySQL原理(一)架构组成(2)逻辑模块组成

总的来说,MySQL可以看成是二层架构,第一层我们通常叫做SQL Layer,在MySQL数据库系统处理底层数据之前的所有工作都是在这一层完成的,包括权限判断,sql解析,执行计划优化,query cache的处理等等&…

Vue之初识Vue CLI 脚手架

Vue CLI 是Vue 官方提供的一个全局命令工具 可以帮助我们快速创建一个开发Vue项目的标准化基础架子。【集成了webpack配置】 脚手架有什么好处? 1.开箱即用,零配置 2.内置 babel 等工具 3.标准化 使用步骤: 1.全局安装(一次):yarn globaladd vue/cli …

私有化部署pdf工具箱

功能简介 用于合并/拆分/旋转/移动PDF及其页面的完全交互式GUI。 将多个 PDF 合并到一个生成的文件中。 将 PDF 拆分为多个文件,并按指定的页码或将所有页面提取为单个文件。 将 PDF 页面重新组织为不同的顺序。 以 90 度为增量旋转 PDF。 删除页面。 多页布局…

STM32学习笔记一——初识STM32

目录 一、什么是ARM 二. Cortex 内核 三.什么是STM32 四.STM32核心板原理图: 五.STM32的内部结构: 六.stm32系统结构简化图 STM32基本原理分析: 七.典型型号——STM32F103ZET6 stm32——32位单片机(数据总线是32位的&am…

文献速递:人工智能医学影像分割--- 深度学习分割骨盆骨骼:大规模CT数据集和基线模型

文献速递:人工智能医学影像分割— 深度学习分割骨盆骨骼:大规模CT数据集和基线模型 我们为大家带来人工智能技术在医学影像分割上的应用文献。 人工智能在医学影像分析中发挥着至关重要的作用,尤其体现在图像分割技术上。这项技术的目的是准…

Flask 入门

1. 关于 Flask Flask诞生于2010年, Armin Ronacher的一个愚人节玩笑。不过现在已经是一个用python语言基于Werkzeug工具箱编写的轻量级web开发框架,它主要面向需求简单,项目周期短的小应用。 Flask本身相当于一个内核,其他几乎所…

前端大屏展示可视化——地图的绘制(持续更新)

一、ECharts 1、安装 npm install echarts2、引入 import * as echarts from echarts;3、渲染 3.1、前期准备,基础配置 // 地图实例 const myChart ref(null); // 地图配置 const option reactive({tooltip: {trigger: item,formatter: function (params) {re…

WebSocket 整合 记录用法

WebSocket 介绍 WebSocket 是基于tcp的一种新的网络协议,可以让浏览器 和 服务器进行通信,然后区别于http需要三次握手,websocket只用一次握手,就可以创建持久性的连接,并进行双向数据传输 Http和WebSocket的区别 Http是短连接,WebSocket’是长连接Http通信是单向的,基于请求…

第十一篇【传奇开心果系列】BeeWare的Toga开发移动应用示例:Briefcase和Toga 哥俩好

传奇开心果博文系列 系列博文目录BeeWare的Toga开发移动应用示例系列博文目录一、前言二、Briefcase和toga各自的主要功能分别介绍三、使用Toga 开发移动应用Briefcase工具是最佳拍档四、Briefcase搭档Toga创建打包发布联系人移动应用示例代码五、运行测试打包发布六、归纳总结…

OCP NVME SSD规范解读-8.SMART日志要求-1

4.8.5章节SMART / Health Information Requirements详细规定了NVMe固态硬盘对SMART(Self-Monitoring, Analysis and Reporting Technology)和健康信息日志页面的支持要求,以确保设备能够准确报告其运行状态和预测潜在故障。 SLOG-1&#xff1…