Flink架构与应用漫聊

一、前言

在如今互联网用户、移动设备、LOT设备、服务等激增的时代下,其产生的数据体量及速率早已不同日而语了。如在刚刚过去的阿里双十一流量洪峰,在Flink实时计算技术的驱动下全程众享丝滑。阿里的实时计算峰值可达到恐怖的4.5+亿次/秒,且数据量也达到了惊人的7TB/秒,然而这么强悍的计算能力背后都离不开Flink的支撑。

Flink已无需再证明自己的能力和价值,所以作为一个大数据工程师你还在苦啃Spark、Hadoop MR、Strom,却还没搞过Flink?不要让自己out了,赶紧跟着本文来好好体验一把,领会其中的奥义吧。

二、简介

2.1 久闻Flink大名那它到底是什么呢

Flink架构与应用漫聊_第1张图片

 图1 Flink Logo

Apache Flink is a framework and distributed processing engine for stateful computations over unbounded and bounded data streams. Flink has been designed to run in all common cluster environments, perform computations at in-memory speed and at any scale.摘自官网对于Flink的定义

官方给的定义极其简洁但阐述的非常清晰,我们来解读一下,大致意思是Apache Flink是一个框架和分布式处理引擎,用于对无界和有界数据流进行状态处理,能运行在常见的集群中,可在任何规模的集群中以内存形式进行分布式计算。

根据定义可以明确的是Flink是一个分布式计算引擎,处理有界和无界的数据流并且可以做到有状态处理,并且还支持内存级别的计算。

2.2 Flink有哪些应用场景

基于Flink的定义我们可以很清晰的分析出它的应用场景,如电商行业的数据报表、双十一的营业额实时统计,物联网(LOT)的传感器数据采集和统计,金融行业的实时对账计算、异常检测,应用的日志实时监控、告警等。总结来说数据产生大且速率快,并且对于计算实时性要求高的情况下均可考虑用Flink作为支撑。

2.3 和SparkStreaming对比

提到分布式计算那必然有Spark的一席之地,Spark问世后,受到了大数据开发者的强烈反响,收获了大量的好评,一度认为是开发者的福音,Spark不但生态完整(包含 Spark Core、SparkSQL、SparkStreaming、MLlib、GraphX),和Hadoop生态整合方便,最重要的是Spark基于RDD模型的分布式计算速度比Hadoop MR提高了不少。这里不过多赘述Spark生态的内容,着重关注SparkStreaming和Flink的一些区别。

两者最大的差异在于运行模型,Spark Streaming 是微批处理,运行的时候需要指定批处理的时间,每次运行 job 时处理一个批次的数据。

Flink架构与应用漫聊_第2张图片图2 spark数据处理模型 来源spark官网

Flink 是基于事件驱动的,事件可以理解为消息。事件驱动的应用程序是一种状态应用程序,它会从一个或者多个流中注入事件,通过触发计算更新状态,或外部动作对注入的事件作出反应。

Flink架构与应用漫聊_第3张图片图3 数据处理模型 来源flink官网 

除了与运行模型,两者的任务调度、时间机制、容错机制上都有所差异,这一节就不具体描述了,在下文会有所提及。

2.4 Flink的其他特点

事件时间语义机制支持丰富,如事件事件(event-time)、处理事件(processing-time)

精确一次(exactly-once)的状态一致性保证机制健全

与常用存储系统兼容性好(如ElasticSearch、Kafka、Redis等)

高可用、动态扩展,能运行在Hadoop组件上

三、运行架构

3.1运行时组件介绍

1.ResourceManager(资源管理器):主要负责Flink运行时资源管理,包括TaskManager、JobManger的资源申请和释放工作

2.JobManager(作业管理器):控制任务运行的主进程,包括生成作业图(JobGraph)、逻辑数据流图(Logical DataFlow Grap)、执行图(ExecutionGraph),负责将任务发送到TaskManager上执行,JobManager会负责所有需要中央协调的操作。

3.TaskManager(任务管理器):

真正运行任务的资源,每个TaskManager都包含一定数量的slot(任务执行的最小单位),在执行过程中可以跟其他运行同一应用程序的TaskManager交换数据。

3.2运行时架构基于Yarn模式):

Flink架构与应用漫聊_第4张图片

图4 yarn模式下运行架构

  1. Flink任务提交后,客户端会向HDFS上传Flink的Jar包和配置信息。(因为Flink是分布式计算,我们提供的Jar包需要每个计算节点都能访问)
  2. 将任务提交到Yarn ResourceManager
  3. ResourceManager申请集群资源并分配Container资源给对应的NodeManager,启动ApplicationMaster,ApplicationMaster加载Flink任务,启动JobManager,作为Flink任务的一个客户端
  4. JobManager经过分析生成ExecutionGraph物理执行图,ApplicationMaster根据物理执行图向ResourceManager申请对应的TaskManager资源
  5. ResourceManager分配Container资源后,由ApplicaitonMaster通知对应NodeManager资源启动TaskManager
  6. NodeManager加载HDFS上的Flink Jar包和构建运行环境启动TaskManager
  7. TaskManager启动后与JobManager保持心跳,等待JobManager给自己分配计算任务

 

四、用法详解

阅读到这里,相信大家在脑海里对于Flink已有了一些自己的认知,想跃跃欲试了?那么本节就重点来讲讲Flink有哪些优秀功能及如何使用它?

4.1 如何创建一个Flink应用

Flink架构与应用漫聊_第5张图片

图5 创建flink应用步骤

如上图所示Flink程序由Source,Transformation、Sink三个核心组件组成。

图中addSource()、addSink()分别表示数据流输入和输出的底层抽象,所以自定义输入和输出会变得非常简单,只需实现底层抽象即可,如作为输入数据流的常用组件HDFS、Kafka都有官方实现,输出数据官方支持同样也很丰富,如ElasticSearch、Kafka、Redis、HDFS等。

4.2 什么是数据流窗口(Window)计算

在流处理应用中,数据是源源不断发送,来一条处理一条不等待,这也是Flink的一大优势,那似乎想对某个时间段内的数据发生计算变的不是很容易(如统计出在过去一分钟内对某个网页的访问量)?因此衍生出了窗口这个概念,Flink认为Batch是Streaming的一个特例,并不影响Flink底层还是一个流式处理引擎的设计初衷。而窗口恰好就是从Streaming到Batch的一个桥梁。所以窗口就是将源源不断的数据流根据你定义的规则划分出不同的区间,每个区间的数据都到齐之后发生最终的窗口计算。Fink内部提供了非常完善的窗口机制,也是Flink的最大的亮点之一。下面来介绍一下窗口的几种类型。

时间窗口 Time Window(支持时间语义event-time、processing-time):

滚动时间窗口:能将数据流切分成不重叠的窗口,每个事件只能属于一个窗口

滑动时间窗口:一个元素可以对应多个窗口,当窗口每次滑动的长度等于窗口大小,效果和滚动事件窗口效果一致。

会话窗口:开启一个窗口,窗口在会话时间段内未受到消息,则视为窗口结束

计数窗口 Count Window(按照元素个数定义):

滚动计数窗口:按照自定义的窗口元素个数来切分成不重叠的窗口,每个事件只能属于一个窗口

滑动计数窗口:一个可能元素对应多个窗口,可定义窗口元素个数和滑动元素个数code:val ds: DataStream[String] = env.addSource(new CustomizeSource())

ds.timewindow(Time.seconds(15)) 滚动时间窗口

ds.timewindow(Time.seconds(15), Time.seconds(15)) 滑动时间窗口

ds.window(EventTimeSessionWindows.withGap(Time.minutes(10)))会话窗口

ds.countwindow(10) 滚动计数窗口

ds.countwindow(10,2) 滑动计数窗口

在章节2 Flink简介中我们提到了“有界”、“无界”的概念,那它和窗口有什么联系吗?

Flink架构与应用漫聊_第6张图片

图6 数据流定义 来源flink官网 

由上图可以看出bounded stream(有界)数据流是有起点和结束点的,而unbounded stream(无界)只有start of the stream(数据起点)并没有看到结束点。所以窗口计算就可以看成是无界的数据流切割为有界流的一种方式,它会将流数据分发到有限大小的桶(bucket)中进行分析。

使用过Spark的同学都知道它一般都是针对大数据做离线计算分析,包括SparkStreaming的微批处理模式,本质上都是对有界数据流的一种分布式计算处理。

4.3 时间语义与watermark

在流处理中时间概念至关重要,因为事件总是在某个时间点或者时间段内发生,所以流数据计算和时间息息相关,例如4.2提到的窗口聚合计算、会话计算等。Flink提供了丰富的时间语义支持。

事件时间模式(event-time):提取数据自带的时间,因此,无论处理的是历史记录的事件还是实时的事件,事件时间模式的处理总能保证结果的准确性和一致性。

处理时间模式(processing-time):根据处理引擎的机器时钟触发计算,一般适用于有着严格的低延迟需求,并且能够容忍近似结果的流处理应用。

在实际编码过程中,可根据业务场景选择对应的时间语义。如需要监控日志异常信息,日志数据往往都自带event-time,这时候采用事件时间模式是最准确的。当然如果业务上并不关心事件发生的时间而更注重在窗口上的计算场景,使用处理时间是最佳的选择。

聊完了时间语义,来试想一个场景,在实际应用场景中,数据一般都是从大集群、分布式环境中不同的数据节点采集而来的,数据很有可能是乱序到达,那在窗口计算过程中能保证在窗口关闭时所有的数据都到齐了吗?显然是不能保证的。针对这种场景Flink引入了watermark的概念,watermark是一种平衡处理延迟和完整性的灵活机制,当带有watermark的事件时间模式处理数据流时,窗口能等待迟到的数据来之后再发生计算,或者将这些数据重定向到侧输出流。

4.4 状态管理

假如我们的计算只针对每一个单独的事件上的转换操作,那我们并不需要状态。可往往并没有那么简单,计算过程通常会产生依赖关系。所以中间的计算结果需要用状态来保存,以供后续的某个时间点进行访问和处理。

Flink架构与应用漫聊_第7张图片

图7 状态管理 来源flink官网

Flink提供了许多状态管理支持:

多种状态基础类型:Flink 为多种不同的数据结构提供了相对应的状态基础类型,例如原子值(value),列表(list)以及映射(map)。开发者可以基于处理函数对状态的访问方式,选择最高效、最适合的状态基础类型。

插件化的State Backend:State Backend 负责管理应用程序状态,并在需要的时候进行 checkpoint。Flink 支持多种 state backend,可以将状态存在内存或者 RocksDB。RocksDB 是一种高效的嵌入式、持久化键值存储引擎。Flink 也支持插件式的自定义 state backend 进行状态存储。

精确一次语义exactly-one:Flink 的 checkpoint 和故障恢复算法保证了故障发生后应用状态的一致性。因此,Flink 能够在应用程序发生故障时,对应用程序透明,不造成正确性的影响。超大数据量状态:Flink 能够利用其异步以及增量式的 checkpoint 算法,存储数 TB 级别的应用状态。

可弹性伸缩的应用:Flink 能够通过在更多或更少的工作节点上对状态进行重新分布,支持有状态应用的分布式的横向伸缩。

定义状态代码实现

//定义一个long类型的ValueState状态

lazy val timerState: ValueState[Long] = getRuntimeContext.getState(new ValueStateDescriptor[Long]("timerState", classOf[Long]))

4.5 Table API与Flink SQL

Table API 是一套内嵌在 Java 和 Scala 语言中的查询API,它允许以非常直观

的方式组合来自一些关系运算符的查询

Flink 的 SQL 支持基于实现了 SQL 标准的 Apache Calcite

Flink架构与应用漫聊_第8张图片

图8  Api模型 来源flink官网

由图可看出TableApi  SQL是对DataStream Api更高层的一个实现它可以将数据流转换成数据表的形式通过写SQL的形式对数据进行分析对于习惯SQL开发的大数据开发工程师来说是一个福音对于曾经熟练使用SparkSQL的开发者来也可以无缝切换降低了学习成本下面来看看如何简单应用

Flink架构与应用漫聊_第9张图片

 图9 table api和flink sql代码实例

Flink对于UDF函数的实现也非常完善,除了内置的substring、max、min、avg、sum常用函数之外,还支持自定义UDF函数,如标量函数、聚合函数、表值函数。这里在着重解释表值函数

Flink架构与应用漫聊_第10张图片

 图10 表值函数实现

熟悉Hive的同学都知道explode + lateral view 的用法,通常也叫侧写函数,这里的表值函数就是侧写函数的一种实现。

举例:原表数据

name

type

战狼

战争、爱国

经过表值函数查询可得到结果

name

type

战狼

战争

战狼

爱国

五、结束语

通过上述4个章节的讲解与用法分析,相信在大家的脑海中留下了一些印象,最后我们对Flink再做一个总结性的回顾。

Flink是一个流式数据分布式处理引擎,具有高吞吐、低延迟的显著特性。并可以实现状态管理编程和窗口计算(watermark解决数据乱序问题),生态完善(集成Kafka、ES、HDFS简单),其中TableApi与FlinkSQL能通过编写SQL语句来实现分布式计算。对于高可用来说,Flink拥有丰富的容错机制及故障恢复后的数据一致性问题解决方案。

因此Flink已经成为我们实时计算领域的带头大哥,不解释任何反驳。对于有类似业务场景的同学赶紧去实战一把吧!

注:本文部分图片和文案摘自官方和网络,仅供读者参考。

你可能感兴趣的:(大数据,spark,hadoop)