欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Flink学习笔记(一):基础概念

程序员文章站 2022-06-17 13:14:27
...

1.有界/*数据集

有界数据集
有界数据集对开发者来说都很熟悉,在常规的处理中我们都会从Mysql,文本等获取数据进行计算分析。我们在处理此类数据时,特点就是数据是静止不动的。也就是说,没有再进行追加。又或者说再处理的当时时刻不考虑追加写入操作。所以有界数据集又或者说是有时间边界。在某个时间内的结果进行计算。那么这种计算称之为批计算,批处理。Batch Processing
*数据集
对于某些场景,类似于Kafka持续的计算等都被认定为*数据集,*数据集是会发生持续变更的、连续追加的。例如:服务器信令、网络传输流、实时日志信息等。对于此类持续变更、追加的数据的计算方式称之为流计算。Streaming Processing

有界数据集与*数据集是一个相对模糊的概念,如果数据一条一条的经过处理引擎那么则可以认为是*的,那么如果每间隔一分钟、一小时、一天进行一次计算那么则认为这一段时间的数据又相对是有界的。有界的数据又可以把数据一条一条的通过计算引擎,造成*的数据集。所以,有界数据集与*数据集可以存在互换的。因此业内也就开始追寻 批流统一 的框架。

能够同时实现批处理与流处理的框架有Apache Spark和Apache Flink,而Apache Spark的流处理场景是一个微批场景,也就是它会在特定的时间间隔发起一次计算。而不是每条都会触发计算。也就是相当于把*数据集切分为小量的有界数据。

Apache Flink基于有界数据集与*数据集的特点,最终将批处理与流处理混合到同一套引擎当中,用户使用Apache Flink引擎能够同时实现批处理与流处理任务。

2.Flink简介

Apache Flink 是由 Apache 软件基金会开发的开源流处理框架,其核心是用 Java 和 Scala 编写的分布式流数据处理引擎。Flink 以数据并行和流水线方式执行任意流数据程序,Flink 的流水线运行时系统可以执行批处理和流处理程序。此外,Flink 的运行时本身也支持迭代算法的执行。
Flink 提供高吞吐量低延迟的流数据处理引擎以及对事件时间处理和状态管理的支持。Flink应用程序在发生机器故障时具有容错能力,并且支持exactly-once语义。
Flink 并不提供自己的数据存储系统,但为Amazon Kinesis、Apache Kafka、HDFS、Apache Cassandra和ElasticSearch等系统提供了数据源和接收器

3.主流数据流处理框架特点比较

  1. Storm:支持低延迟,但是很难实现高吞吐,并且不能保证 exactly-once
  2. Sparking Streaming ( Storm Trident ):利用微批处理实现的流处理(将连续事件的流数据分割成一系列微小的批量作业),能够实现 exactly-once 语义,但不可能做到完全实时(毕竟还是批处理,不过还是能达到几秒甚至几亚秒的延迟)
  3. Flink:实时流处理,支持低延迟、高吞吐、exactly-once 语义、有状态的计算、基于事件时间的处理

相对来说,Flink实现了真正的流处理,并且做到了低延迟高吞吐exactly-once 语义;同时还支持有状态的计算(即使在发生故障时也能准确的处理计算状态) 和 基于事件时间的处理

4.Flink 基本架构

Flink学习笔记(一):基础概念
Flink主要有两类进程: JobManager 和 TaskManager

  • JobManager(masters): 协调分布式计算、任务调度,协调checkpoints,错误调度等,相当于一个指挥官吧(实际部署时,至少需要一个 JobManager,实际生产环境部署时都会做HA,部署多个JobManager;这个时候,只有一个leader,其他都是standby模式)
  • TaskManager(workers):真正执行dataflow的,并对streams进行缓存和交换

总的来说,运行中的 Flink 集群至少有一个 JobManager 进程和一个TaskManager 进程。如果将客户端也算进去的话,那么还有一个 Client 进程。各个进程一般部署在不同的机子上,不过也可以部署在同一台机子上,就比如说在本地启动一个集群时( Local 模式,通常用于开发调试 ), JobManager 进程和 TaskManager 进程就是跑在同一台服务器上。Flink 是基于 Akka Actor 实现的 JobManager 和 TaskManager,所以JobManager和 TaskManager 以及 Client 之间的信息交互都会通过事件的方式来进行处理的。
一个简单的流程就是,Client 提交任务作业给 JobManager ,JobManager 负责该作业的调度和资源分配(在 Flink 集群中,计算资源被定义为 Task Slot。每个 TaskManager 会拥有一个或多个 Slots),随后将作业分给对应的 TaskManager,TaskManager 收到任务后,启动线程去执行,并向 JobManager 报告任务状态和自身运行状态等。当任务结束后, JobManager 将收到通知,并统计数据后发送给 Client。

5.Flink编程模型

Flink 处理数据流的时候,一般遵循如下模型:
构建 Flink 程序最基本的模块就是数据流和算子( transformations ),数据流就是永不终止的数据记录,而算子将数据流作为输入,进行特定操作后,再产生新的流数据。
通常,其处理流程为 Source -> Transformations -> Sink . 其数据流构成一个有向无环图(DAG)。
Flink学习笔记(一):基础概念
其中 Transformation Operators 有多种,DataSet APIDataStream API 支持的不完全相同,通常支持的有如下几种,更详细的可以参考官方文档;

Transformations 描述
Map (DataSet 和 DataStream 都有) 将一个元素经过特定处理映射成另一个
Filter (DataSet 和 DataStream 都有) 经过特性函数处理,过滤数据
KeyBy (Only DataStream ) 将数据根据特定的属性字段分区
Window 按需将KeyedStreams分组处理

Source 为待处理数据的输入地,而 Sink 为处理后的输出地,目前 Flink 支持的 Source 和 Sink 有:

  • Apache Kafka (source/sink)
  • Apache Cassandra (sink)
  • Amazon Kinesis Streams (source/sink)
  • Elasticsearch (sink)
  • Hadoop FileSystem (sink)
  • RabbitMQ (source/sink)
  • Apache NiFi (source/sink)
  • Twitter Streaming API (source)
  • Apache ActiveMQ (source/sink)
  • Apache Flume (sink)
  • Redis (sink)
  • Akka (sink)
  • Netty (source)

6.对时间的处理

一般来说,在流数据处理中,可以将时间分成三类:

  • 事件时间:事件实际发生的时间(流记录中本身包含对应的时间戳)
  • 处理时间:事件被处理的时间(被流处理器处理的时间)
  • 进入时间:事件进入流处理框架的时间(缺乏真实事件时间的数据会被流处理器附上时间戳,即流处理器第一次看到他的时间)

Flink 允许用户根据自己所需来选择三者中的任何一种来定义时间窗口。

7. 窗口

窗口是一种机制,其将许多事件按照时间或者其他特征分组,从而将每一组作为整体进行分析。Flink 目前默认支持有时间窗口,计数窗口,会话窗口。
时间窗口
时间窗口,应该算是比较常用的一个窗口处理了。比如说,每分钟统计一次某商品的点击数啊;或者每分钟统计一次一个小时内点击数最高的前十个产品之类的需求。只要是按照时间划分的,都可以使用时间窗口。
时间窗口又分为滚动时间窗口和滑动时间窗口两种。

下面图解下滚动窗口和滑动窗口的区别 :

  1. 滚动窗口
    Flink学习笔记(一):基础概念
    代码示例:定义一个一分钟的滚动窗口
stream.timeWindow(Time.minutes(1))
  1. 滑动窗口
    Flink学习笔记(一):基础概念
    代码示例:定义一个窗口大小为一小时,滑动周期为一分钟的滑动窗口
stream.timeWindow(Time.minutes(60), Time.minutes(1))

计数窗口
技术窗口和时间窗口类似,只不过分组依据不是时间而是数据个数,同样也分滚动计数窗口和滑动计数窗口,这里不再细说。
代码示例:

stream.countWindow(100); // 滚动计数窗口
stream.countWindow(100, 10); // 滑动计数窗口

使用计数窗口需要考虑,万一最终的数据量一直无法满足窗口大小的量,那么该程序可能就无法终止,最好设置超时。
会话窗口
不像前两种,这个比较特别。需要先理解什么算一个会话: 会话指的是活动阶段,其前后都是非活动阶段,那么这一活动阶段就是一个有效的会话。会话阶段通常需要有自己的处理机制,可以想象,会话的定义比较灵活,很难有固定的会话定义。Fink 也支持一些简单的定义直接使用。
代码示例:

stream.window(SessionWindows.withGap(Time.minutes(5)); // 五分钟内没有活动的话,则认为会话结束 

8.时间和水印(Watermarks)

支持事件时间的流处理器需要明确的知道何时才是事件事件的终止。就好比一个一小时的时间窗口操作,我们需要知道何时才是真正的结束时间,否则窗口无法被正确的关闭( 因为实际,基于事件时间的事件其由于网络等原因,其到达的顺序并不一定就是其事件发生时间的顺序 )。另外,在 Kappa 架构中, 流数据处理框架需要支持处理回放的数据,那么同一组数据重新运行同样的程序,需要得到相同的结果,这也需要其支持事件时间,因为如果窗口的设定是根据系统时间而不是事件自带的时间戳,那么每次运行同样的程序,都会得到不同的结果。
可见支持事件时间对于流处理架构而言至关重要,因为事件时间能保证结果正确,并使流处理架构拥有重新处理数据的能力。那么 Flink 是如何做到对事件时间的支持的? 其实际是通过 Watermarks 机制来实现的。

Watermarks 作为数据流中的一部分,包含一个时间戳 t,当处理器处理到这个 Watermark(t) 的时候,就认为所有事件时间小于该水印时间的事件数据都已经到达。
但是即使如此,依然可能会有些事件数据在 Watermark 之后到达,这时 Watermark 机制也无法起到对应的作用,针对这一情况 Flink 支持了 Late Elements 处理,详情查看官网 Allowed-lateness

9.有状态计算

流计算一般分为有状态和无状态两种,无状态计算指的是处理过程中不依赖于之前的数据处理结果或其他中间数据;而有状态的计算会维护状态,并基于最新数据和当前状态生成输出结果。
Flink学习笔记(一):基础概念
有状态的计算引入了状态,所有引入了状态的分布式系统都会遇到一个数据一致性的问题。流处理或消息系统中,通常将其定义为 “正确性级别”, 通常来说会有三个级别:

  • at-most-once: 数据可能会丢失
  • at-least-once:数据最少处理一次,但可能会重复
  • exactly-once:数据均被且只被处理一次

Flink 支持 exactly-once 语义,且还能保持低延迟和高吞吐的处理能力,这是 Flink 的一个重大优势。Flink 保证 exactly-once 主要是通过他的 checkpoint 和 savepoint 机制。
checkpoint: Flink 自动周期生成,用于用户程序出故障时,使其重置回到正确的状态,主要需做两件事

  1. 保存source中流的偏移量( eg. kafka数据的便宜量,以便数据重放)
  2. 保存中间的计算状态( 即StateBackend,这个保存的位置可以选择,后面再讲)

Flink 检查点算法的正式名称是异步屏障快照(asynchronous barrier snapshotting)。该算法大致基于Chandy-Lamport 分布式快照算法。
其中,有一个核心的概念:Barrier(屏障)
在数据流中,屏障和普调标记类似;他们都由算子处理,但是不参与计算,而是会触发与检查点相关的行为。当读取输入流的数据源遇到检查点屏障时,它将其在输入流的位置保存到文档存储中(eg. kafka的偏移量)。当算子处理完记录并收到了屏障时,它们会将状态异步保存到稳定存储中,当状态备份和检查点位置备份都被确认后,则认为该检查点已完成。
总结下:

  • Souce 遇到屏障保存数据位置
  • 算子遇到屏障异步保存状态
  • 保存结束后确认检查点完成

savepoint: 需要应用自己手动生成,通常用于状态版本控制。依赖于checkpoint机制。
上述流程中涉及到保存状态,Flink 可以支持多种状态存储。大致有以下几种StateBackend

  • MemoryStateBackend 快速,但是不稳定,重启就没了。
  • RocksDBStateBackend 支持增量,支持大状态长窗口的大数据存储,但是存储和读取时都需要序列化(会耗时)
  • FsStateBackend 支持大状态长窗口的大数据存储,但是还是会保存一份在 TaskManager 的 Memory 中,所以状态的大小不能超过 TaskManager 的内存