Flink-2-流处理基础

第2章 流处理基础

参考书籍编程

注:本文主要是针对《基于Apache Flink的流处理》的笔记服务器

1-8章笔记下载地址网络

本章的目标是介绍流处理的基本概念以及对其处理框架的要求。session

2.1 Dataflow编程概述

2.1.1 Dataflow图

Dataflow程序一般表示为有向图并发

  • 其中节点称为算子,表明计算,表明数据依赖
  • 算子数据流应用程序基本功能单元。它们从输入中获取数据,对数据进行计算,而后将数据输出到输出端进行进一步处理。
  • 没有输入端的算子称为数据源没有输出端的算子称为数据汇
  • 数据流图必须至少一个数据源一个数据汇

图2-1显示了一个数据流程序,它从文章的输入流中提取并计数一些标签。app

image-20201029121349342

像图2-1中的数据流图被称为逻辑图,由于它们传达了计算逻辑的高级视图。为了执行数据流程序,它的逻辑图被转换成物理Dataflow图,该图详细说明了程序是如何执行的。例如,若是咱们使用分布式处理引擎,每一个 算子可能有几个并行任务在不一样的物理机器上运行。负载均衡

图2-2显示了图2-1的逻辑图的物理数据流图。在逻辑Dataflow图中,节点表明算子,而在物理Dataflow图中,节点表明任务。每一个任务负责计算一部分的输入数据。框架

2.1.2 数据并行和任务并行

能够以不一样的方式利用数据流图中的并行性。

首先,能够对某个算子输入数据进行分区,并在数据子集并行执行相同操做的任务。这种类型的并行称为数据并行。数据并行很是有用,由于它容许将大量计算数据分布到多个不一样的物理节点上并行执行。

其次,可让不一样算子任务 并行执行相同或不一样数据的计算。这种类型的并行称为任务并行。使用任务并行,能够更好地利用集群的计算资源。

2.1.3 数据交换策略

数据交换策略定义了数据项如何被分配给物理Dataflow图中的不一样任务。在这里,咱们简要介绍一些常见的数据交换策略,如图2-3所示。

  • 转发策略发送端任务接收端任务之间一对一地进行数据传输。若是两个任务位于同一个物理机器上(这一般由任务调度器来保证),这种交换策略避免了网络通讯。
  • 广播策略每一个数据项发送给算子的全部并行任务。由于这种策略复制数据并涉及网络通讯,因此成本至关高。
  • 基于键值的策略经过键属性划分数据,并保证具备相同键的数据项由相同的任务处理
  • 随机策略将数据项均匀随机分配给任务,以便负载均衡

2.2 并行流处理

下面看看如何将Dataflow的概念运用到并行数据流处理中。咱们先给出数据流的定义:数据流是一个长度可能无限长的事件序列

数据流的例子以下:监控器产生的监控数据、传感器产生的测量数据、信用卡交易数据、气象站观测数据、搜索引擎搜索记录等

2.2.1 延迟和吞吐

对于批处理应用程序,咱们一般关心做业的总执行时间,或者咱们的处理引擎读取输入、执行计算和写回结果须要多长时间。因为流应用程序连续运行,而且输入多是无限的,所以在流处理没有总执行时间的概念。取而代之的是,流处理必须尽量地为传入数据提供结果(延迟),同时还要应对很高的事件输入速率(吞吐)。咱们用延迟和吞吐来表示这两方面的性能需求。

2.2.1.1 延迟

延迟表示处理一个事件所需的时间。本质上,它是接收事件到在输出中看到事件处理效果的时间间隔。

在数据流中,延迟以时间为单位进行衡量,例如毫秒。根据应用程序的不一样,可能会关心平均延迟最大延迟百分比延迟。例如,10ms的平均延迟意味着平均在10ms内处理事件。或者,10毫秒的95%延迟值意味着95%的事件在10毫秒内获得处理。

像Apache Flink这样的现代流处理引擎能够提供低至几毫秒的延迟。

2.2.1.2 吞吐

吞吐量是对系统处理能力的一种度量——它的处理速率。也就是说,吞吐量告诉咱们系统每单位时间能够处理多少个事件

须要注意的是,处理的速率取决于事件到达速率;低吞吐量不必定表示性能差。在流式系统中,一般但愿确保系统可以处理最大的预期事件到达速率。也就是说,主要关心的是肯定峰值吞吐量,即系统处于最大负载时的性能限制。

一旦事件到达速率超过了预期的最大值,咱们就不得不开始缓冲事件。若是系统继续以超过其处理能力的接收速率接收数据,缓冲区可能会变得不可用,数据可能会丢失。这种状况一般被称为背压

2.2.1.3 延迟与吞吐

此时,应该清楚的是,延迟吞吐 不是独立的指标

  • 若是事件须要很长时间才能在数据处理管道中传输,咱们就没法轻松确保高吞吐量(延迟影响了吞吐)。
  • 一样,若是系统的处理能力太低,事件将被缓冲,必须等待才能获得处理(吞吐影响了延迟)。

下降延迟可提升吞吐量。若是一个系统能够更快地执行操做,它能够在相同的时间内执行更多的操做。而一个很好的方式就是并行处理

2.2.2 数据流上的操做

流处理引擎一般提供一组内置操做来接收、转换和输出数据流。这些操做能够用来构成Dataflow图表明流式应用的逻辑。在本节中,咱们将介绍最常见的流式操做

操做能够是无状态的,也能够是有状态的。

  • 无状态操做不维护任何内部状态。也就是说,一个事件的处理 不依赖于 任何历史事件,也不保留历史数据。无状态操做很容易并行化
  • 有状态操做会维护他们之前接收到的事件的信息状态经过传入的事件更新,而且在将来事件处理逻辑中使用。有状态流处理应用程序在并行化容错方面更具挑战性
2.2.2.1 数据接入和数据输出

数据接入和数据输出操做容许流处理器与外部系统通讯。

数据接入是从外部系统 获取原始数据并将其转换为适合处理格式的操做。实现数据接入逻辑算子称为数据源

数据输出是以适合外部系统使用的形式产生输出的操做。实现数据输出算子称为数据汇

2.2.2.2 转换操做

转换操做是单程操做(single-pass),每一个事件独立处理。操做一个接一个处理事件,并对事件数据进行一些转换,产生一个新的输出流。通常来讲,转换操做比较简单,不用维护内部状态

转换操做的算子能够接受多个输入并产生多个输出流。他们还能够经过将一个流分红多个流或将多个流合并成一个流来修改数据流图的结构。

2.2.2.3 滚动聚合

滚动聚合是针对每一个输入事件不断更新聚合操做,好比总和最小值最大值聚合操做有状态的,并将当前状态传入事件相结合生成新的聚合值。图2-5显示了一个滚动最小聚合。操做符保持当前的最小值,并针对每一个传入事件相应地更新它。

2.2.2.4 窗口操做

转换滚动聚合 每次处理一个事件,以生成输出事件并更新状态。可是,有些操做必须收集缓存事件。例如求中位数的函数。为了在无限流高效地计算这些操做,须要限制这些操做维护的数据量。在本节中,咱们将讨论窗口操做

窗口还支持在数据流进行一些有趣的查询。例如:若是有一个为司机提供实时交通讯息的应用程序。在这个场景中,您想知道在过去几分钟内某个位置是否发生了拥堵。这时候咱们只关注过去几分钟这个窗口的数据。

窗口操做不断地从一个无界事件流建立 长度有限的事件集(称为),并让咱们对这些 执行计算。事件一般根据数据属性或时间分配到桶中。窗口的行为一组策略定义窗口策略决定什么时候建立新的存储桶,将哪些事件分配给哪些存储桶,以及什么时候计算桶中的数据。窗口策略指定能够基于时间数量其余数据属性

下面介绍常见的窗口类型的语义

2.2.2.4.1 滚动窗口

滚动窗口事件分配长度固定不重叠的桶中。当窗口边界经过时,全部事件都被发送到一个计算函数进行处理。基于计数的滚动窗口定义了在触发评估以前收集了多少事件。图2-6显示了一个基于计数的滚动窗口,它将输入流分到四个元素组成的桶。基于时间的滚动窗口定义了桶中事件的时间间隔。图2-7显示了一个基于时间的滚动窗口,它将事件收集到桶中,并每10分钟触发一次计算。

2.2.2.4.2 滑动窗口

滑动窗口将事件分配到固定大小容许互相重叠的桶中。所以,一个事件 可能属于多个桶。咱们经过指定桶的长度滑动间隔来定义滑动窗口。图2-8中的窗口长度为4,滑动间隔为3。

2.2.2.4.3 会话窗口

会话窗口在常见的现实场景中很是有用,在这些场景中,滚动窗口和滑动窗口都不能应用。考虑一个分析在线用户行为的应用程序。在这样的应用程序中,咱们但愿未来自同一会话事件分到一组

会话窗口根据会话间隔(session gap)对事件进行分组,会话间隔定义了认为会话已关闭的非活动时间。(也就是若是用户在很长的一段时间内没有与服务器通讯就认为他的会话已经关闭了)

窗口操做与流处理中的两个主要概念密切相关:时间语义状态管理

  • 流数据一般会有延迟或者乱序到达,这时如何保证窗口正确划分就很重要
  • 此外,为了不故障,须要在生成结果以前将窗口中的数据都采起安全措施保护起来

2.3 时间语义

2.3.2 处理时间

处理时间机器本地时钟的时间。处理时间窗口包括在一段时间内** 碰巧到达窗口全部事件,由机器的本地时钟测量。如图2-12所示

2.3.3 事件时间

事件时间是流中的事件实际发生时间。事件时间经过附加到流事件时间戳来判断。

图2-13显示:即便事件有延迟,事件时间窗口也能准确地把事件分配到正确的窗口中,从而反映事情发生的真实状况

不管数据流的处理速度有多快,事件到达算子的顺序是怎样的,事件时间窗口的计算将产生相同的结果。

经过依赖事件时间,即便是在无序数据的状况下,咱们也能够保证结果的正确性。此外,当与可重放的流结合时,时间戳的肯定性使你可以回到过去。也就是说,你能够重放一个流并分析历史数据,就像事件是实时发生的同样。

2.3.4 水位线

到目前为止,在咱们关于事件时间窗口的讨论中,咱们忽略了一个很是重要的方面:咱们如何决定事件时间窗口触发时机(何时中止收集并开始计算)?也就是说,咱们要等多久才能肯定咱们已经收到了某个时间点以前发生的全部事件?考虑到分布式系统的不可预测性和由外部带来的各类延迟,这些问题没有绝对正确的答案

水位线(watermark)是一种全局进度度量,它是一个时间点。它代表咱们确信这个时间点以前的事件所有到达了。本质上,水位线提供了一个逻辑时钟,通知系统当前的事件时间。当操做员收到时间为T的水位线时,能够假设不会再收到时间戳小于T的事件。水位线对于事件时间窗口和处理无序事件的算子都是必不可少的。

水位线提供告终果可信度和延迟之间trade-off

  • 激进的水位线确保低延迟,但提供较低可信度
  • 保守的水位线带来高延迟,但同时带来较高可信度

流处理系统会提供某种机制处理水位线以后到达的事件。

2.3.5 处理时间与事件时间

此刻你可能会想,既然事件时间解决了咱们全部的问题,为何咱们还要去关心处理时间?

事实是,在某些状况下,处理时间确实颇有用。

  • 处理时间窗口引入了尽量低的延迟
  • 当你须要按期实时报告结果时,可是不太关注结果的精度时,处理时间是更合适的。
  • 最后,处理时间窗口提供了流自己的真实状况,这对于一些用例来讲多是一个理想的属性。

2.4 状态和一致性模型

状态在数据处理中无处不在。任何复杂一点的计算都须要它。为了产生结果,函数在一段时间或多个事件上累积状态(例如,计算汇集或检测模式)。有状态算子使用传入事件内部状态计算它们的输出更新状态

在连续运行的流做业中,状态在事件之间是持久的,咱们能够在编程模型中将其做为一级公民公开。而在以前的批处理中,后一个批次的数据是看不到前一个批次的数据的。

因为流操做引擎有可能处理的是无限流,所以应当心不要让内部状态无限增加。为了限制状态的大小,算子一般会对到目前为止看到的事件进行某种总结概要。这样的摘要能够是计数总和、迄今为止所看到的事件的抽样窗口缓冲区。

支持有状态算子会带来不少实现上的挑战:

  1. 状态管理:系统须要有效地管理状态,并确保它不受并发更新的影响
  2. 状态划分:并行化变得复杂,由于结果取决于状态和传入的事件。幸运的是,在许多状况下,您能够经过一个键来划分状态,并独立管理每一个分区的状态。例如,好比正在处理来自一组传感器的测量流,能够用不一样的分区来处理不一样的传感器。
  3. 状态恢复:有状态操做符带来的第三个也是最大的挑战是确保状态能够恢复,而且即便在出现故障的状况下结果也是正确的。

2.4.1 任务故障

流式做业中的算子状态很是重要,应防止出现故障。若是状态在故障期间丢失,恢复后的结果将是不正确的。流处理引擎不只须要保证在出现任务故障时能够正常运行,还须要保证结果和算子状态的正确性。

对于输入流中的每一个事件,任务执行如下步骤:

  1. 接收事件,将其存储在本地缓冲区中;
  2. 更新内部状态
  3. 产生输出记录。

在这些步骤中的任何一个均可能发生故障,系统必须清楚地定义其在每种故障场景中的如何处理。例如,一个定义完整的流式处理系统须要明确如下问题:若是任务在第一步失败,事件会丢失吗?若是在更新了内部状态后失败了,恢复后还会再更新吗?而在上面这些状况下,输出仍是正确的吗?

2.4.2 结果保障

在批处理场景中,全部这些问题都获得了回答,由于批处理做业能够简单地从头开始从新启动。所以,没有事件丢失,状态彻底是从零开始创建的。然而,在流处理中,这些问题很棘手。流式系统经过提供结果保障(result guarantee)来定义它们在出现故障时的行为。接下来,咱们回顾了现代流处理引擎提供的几种不一样级别的结果保障。

2.4.2.1 至多一次(AT-MOST-ONCE)

当任务失败时,最简单的方法就是不作任何事情来恢复丢失的状态和重放丢失的事件。至多一次只保证每一个事件至多处理一次。换句话说,系统能够简单地丢弃事件,不作任何事情来确保结果的正确性。这种类型的保障也被称为“无保障”,由于即便是系统丢弃全部事件也能够提供这种保证。

2.4.2.2 至少一次(AT-LEAST-ONCE)

在大多数现实世界的应用程序中,人们指望事件不会丢失。这种类型的保证被称为至少一次这意味着全部事件都将被处理,而且其中一些事件有可能被处理屡次。若是应用程序的正确性仅取决于信息的完整性,重复处理多是能够接受的。

为了确保至少一次这种结果保障,须要有一种方法来重放(replay)事件——要么从源(source),要么从某个缓冲区(buffer)。

下面介绍两种保证至少一次的方式

  1. 持久事件日志将全部事件写入持久存储,以便在任务失败时能够重放(replay)。
  2. 另外一种方法是使用记录确认。此方法将每一个事件存储在缓冲区中,直到管道中的全部任务都确认这个事件已经处理过了,此时能够丢弃该事件。
2.4.2.3 精确一次(EXACTLY-ONCE)

精确一次是最严格的保证,也很难实现。它意味着不只不会有事件丢失,并且每一个事件只容许处理一次。从本质上来讲,精确一次意味着咱们的应用程序将提供彻底正确的结果,就好像从未发生过失败同样

精确一次以致少一次为前提的,所以数据重放机制必不可少。

并且在故障恢复以后,处理引擎应该知道一个事件的更新是否已经反映在状态上。有两种实现方式:

  • 事务性更新是实现这一结果的一种方式,可是它们会致使大量的性能开销。

  • 相反,Flink使用轻量级快照机制来实现一次结果保证

2.4.2.4 端到端精确一次(END-TO-END EXACTLY-ONCE)

端到端保证指的是整个数据处理流水线上的结果正确性。流水线上的每一个组件都提供本身的保证,完整管道的端到端保证将由全部组件中最弱的那个组件来决定。有时候弱的保障可能会表现出强的语义,好比,你使用至少一次来求最大值或者最小值,管道的其余组件都使用精确一次,那么这个管道也是端到端精确一次的。

相关文章
相关标签/搜索