一、概述

在大数据应用场景里,一般可将数据计算分为离线计算实时计算,其中离线计算就是我们通常说的批计算处理,主要用于操作大容量的静态数据集,代表技术有Hadoop MapReduce、Hive等;实时计算也被称作流计算,代表技术是Storm、Spark Streaming、Flink等。其中,Flink即Apache Flink,它是由Apache软件基金会开发的开源流处理框架,基于Apache许可证2.0开发,其核心是用Java和Scala编写的分布式流数据流引擎。Flink以数据并行和流水线方式执行任意流数据程序,Flink的流水线运行时系统可以执行批处理和流处理程序。每个Flink数据流以一个或多个源(数据输入,例如消息队列或文件系统)开始,并以一个或多个接收器(数据输出,如消息队列、文件系统或数据库等)结束。Flink 能在所有常见集群环境中运行,并能以内存速度和任意规模进行计算。Flink具有Web UI,可以检查,监视和调试正在运行的应用程序。它还可以用于提交执行以执行或取消执行。

flink 实现数据分析 flink的数据存储在哪_flink 实现数据分析


Apache Flink 功能强大,支持开发和运行多种不同种类的应用程序。它的主要特性包括:批流一体化精密的状态管理事件时间支持以及精确一次的状态一致性保障等。Flink 不仅可以运行在包括 YARN、 Mesos、Kubernetes 在内的多种资源管理框架上,也支持在裸机集群上独立部署。在启用高可用选项的情况下,甚至基本不存在单点失效问题。相关经验事实证明,Flink 已经可以扩展到数千核心,其状态可以达到 TB 级别,且仍能保持高吞吐低延迟的特性。已经有很多要求严苛的流处理应用都运行在 Flink 之上。流应用需保证最少的停机时间内连续运行,因此流处理器必须提供出色的故障恢复能力,以及在运行时监控和维护应用程序的工具。Apache Flink将重点放在流处理的操作方面,它具备有效的故障恢复能力;

flink 实现数据分析 flink的数据存储在哪_flink 实现数据分析_02


Flink提供了一些功能来确保应用程序保持运行并保持一致:

  • 一致性检查点:Flink的故障恢复机制是通过建立在应用程序状态一致性检查点实现的,如果发生故障,将重新启动应用程序,并从最新的检查点加载其状态。结合可重置的数据源,从而可以保证一次状态一致性。
    \
  • 高效的检查点:如果一个应用程序要维护TB量级的状态信息,那么对应用程序的状态进行检查点的开销可能是会非常昂贵。Flink可以执行异步增量检查点,大大减少检查点对应用程序延迟SLA的影响。
    \
  • 端到端的精确一次:Flink具有针对特定存储系统的事务接收器,即使在发生故障的情况下,也可以确保仅将数据精确地写入一次
    \
  • 与集群管理器的集成:Flink与Hadoop YARN,Mesos或Kubernetes等集群管理器紧密集成。当某个流程失败时,新流程将自动启动以接管其工作。
    \
  • 高可用性服务的设置:Flink具有高可用性模式,以消除可能的单点故障。HA模式是基于Apache ZooKeeper实现的,实现可靠的分布式协调服务。
    \
  • Flink提供了保存点(状态快照)的功能,以解决更新有状态的应用程序的问题以及其他相关的挑战。保存点是应用程序状态的一致性快照,与检查点非常的相似。与检查点相比,保存点需要手动触发,并且在停止应用程序时不会自动被删除,保证了保存点可用于启动状态兼容的应用程序并初始化恢复状态。使用保存点,可以将应用程序迁移(或克隆)到不同的群集。可便于A/B测试及假设分析场景对比结果(可以通过从同一保存点启动所有版本来比较应用程序的两个(或多个)不同版本的性能或质量。)
    \
  • 对持续运行的流应用程序进行监控并将其集成到运营基础架构中,例如一个组件的监控服务及日志服务等。监控有助于预测问题并提前做出反应。通过日志服务,可以分析调查故障发生的根本原因,另外,一个易于控制运行中的应用程序访问的接口是一个重要的功能。Flink与许多常用的日志记录和监视服务很好地集成在一起,并提供REST API来控制应用程序和查询信息。Flink实现流行的slf4j日志记录接口,并与日志记录框架log4j或logback集成。Flink具有复杂的指标系统,用来收集并报告系统和用户定义的指标。指标可以导出到多个报告器,包括JMX,Ganglia,Graphite,Prometheus,StatsD,Datadog和Slf4j。link提供了REST API来提交新应用程序,获取正在运行的应用程序的保存点或取消应用程序。REST API还提供了正在运行或已完成的应用程序的元数据和收集的指标。

除了外国的一些公司,国内很多厂商也应用了Flink来应对流处理场景,那它们的Flink 做了什么呢?

  • Alibaba 使用 Flink 的分支版本 Blink 来优化实时搜索排名。比如当商家上架一个商品之后,实时计算引擎(Flink)可在秒级别 build 商品索引,优化商品搜索。
    \
  • 腾讯利用 Apache Flink 构建了一个内部平台(Oceanus),以提高开发和操作实时应用程序的效率。
    \
  • 快手使用了 Apache Flink 搭建了一个实时监控平台,监控短视频和直播的质量。

    滴滴使用 Apache Flink支持了实时监控、实时特征抽取、实时ETL等业务。

更多企业应用案例,参看Flink confluence

其他相关参考:Flink中文社区Apache FlinkApache YarnApache Mesos

二、架构

Flink 可以运行在多种不同的环境中,如:它可以单进程多线程的方式直接运行,从而提供调试的能力。也可以运行在 Yarn 或者 K8S 这种资源管理系统上面,或在各种云环境中执行。Flink 运行时由两种类型的进程组成:一个 JobManager 和一个或者多个 TaskManager。Flink架构分为3个部分,client,JobManager(简称JM)和TaskManager(简称TM)。client负责提交用户的应用拓扑到jm(和spark的driver用法不同),flink的client只是单纯的将用户提交的拓扑进行优化,然后提交到jm,不涉及任何的执行操作。jm负责task的调度,协调checkpoints,协调故障恢复等。tm负责管理和执行task。另外,它内置了一个符合 ANSI 标准的 SQL 接口,将批、流查询的语义统一起来。无论是在记录事件的静态数据集上还是实时事件流上,相同 SQL 查询都会得到一致的结果。同时 Flink 还支持丰富的用户自定义函数,允许在 SQL 中执行定制化代码。如果还需进一步定制逻辑,可以利用 Flink DataStream API 和 DataSet API 进行更低层次的控制。Flink 的 Gelly 库为基于批量数据集的大规模高性能图分析提供了算法和构建模块支持。

flink 实现数据分析 flink的数据存储在哪_hadoop_03


Flink以层级式系统形式组件,其软件栈、上层依赖下层服务,支持 local、cluster、cloud运行模式;运行时,将dataStream 和 dataSet抽象成jobGraph;Flink目前支持 4 层抽象,最常用的是在 Core API 的使用,Streaming API 和 Batch API 的使用。

flink 实现数据分析 flink的数据存储在哪_数据_04

2.1、整体架构及原理

flink 实现数据分析 flink的数据存储在哪_big data_05


Flink的3个组件,在其第一次启动时,会创建各自的进程,且分别在独立的jvm里运行,一般会启动一个 JobManger 和一个或多个的 TaskManager。由 Client 提交任务给 JobManager, JobManager 再调度任务到各个 TaskManager 去执行,然后 TaskManager 将心跳和统计信息汇报给 JobManager,TaskManager 连接到 JobManagers,宣布自己可用后,才会被分配工作。TaskManager 之间以流的形式进行数据的传输。但Client 斌不是运行时和程序执行的一部分,而是用于准备数据流并将其发送给 JobManager的。它提交 Job 后,Client 可以结束进程 (Streaming的任务)(分离模式),也可以不结束并等待结果返回(附加模式)。对比YARN架构:

flink 实现数据分析 flink的数据存储在哪_hadoop_06


Flink on Yarn:

flink 实现数据分析 flink的数据存储在哪_数据_07

对比Mesos架构:

flink 实现数据分析 flink的数据存储在哪_flink_08


Flink架构中的组件交互:

flink 实现数据分析 flink的数据存储在哪_flink 实现数据分析_09


flink 实现数据分析 flink的数据存储在哪_数据_10


Flink 组件说明:

1、JobManager :JobManager 主要负责协调 Flink 应用程序的分布式执行,如它决定何时调度下一个 task(或一组 task)、对完成的 task 或执行失败做出反应、协调 checkpoint、并且协调从失败中恢复等等。始终至少有一个 JobManager。高可用(HA)设置中可能有多个 JobManager,其中一个始终是 leader,其他的则是 standby这个进程又由三个不同的组件组成:
\

1)Resource Manager

ResourceManager 负责 Flink 集群中的资源提供、回收、分配 -它管理 task slots(Flink 集群中资源调度的单位)。Flink 可为不同的环境和资源提供者(例如 YARN、Mesos、Kubernetes 和 standalone 部署)实现了对应的 ResourceManager。在 standalone 设置中,ResourceManager 只能分配可用 TaskManager 的 slots,而不能自行启动新的TaskManager。

2)Dispatcher

Dispatcher 提供了一个 REST 接口,用来提交 Flink 应用程序执行,并为每个提交的作业启动一个新的 JobMaster。它还运行 Flink WebUI 用来提供作业执行信息。

3)JobMaster

JobMaster 负责管理单个JobGraph的执行。Flink 集群中可以同时运行多个作业,每个作业都有自己的 JobMaster。

2、TaskManagers

TaskManager(也称为 worker)执行作业流的 task,并且worker之间缓存和交换数据流。必须始终至少有一个 TaskManager。在 TaskManager 中资源调度的最小单位是 task slot。TaskManager 中 task slot 的数量表示并发处理 task 的数量。请注意一个 task slot 中可以执行多个算子。

Flink通信流程:

flink 实现数据分析 flink的数据存储在哪_hadoop_11

Flink把任务调度管理和真正执行的任务进行了分离(物理分离)。对比spark的调度和执行任务是在一个jvm里的,也就是driver。分离的好处很明显,不同任务可以复用同一个任务管理(jm,tm),避免多次提交,缺点需要额外提交维护tm。

flink 实现数据分析 flink的数据存储在哪_flink_12

flink 实现数据分析 flink的数据存储在哪_hadoop_13


flink 实现数据分析 flink的数据存储在哪_hadoop_14

2.2、相关概念

1)批处理和流处理的区别

批处理主要操作大容量的静态数据集,并在计算过程完成之后返回结果。流处理系统需要对随时进入系统的数据进行实时计算。批处理和流处理的差异主要体现在:首先,流处理中的数据集是无边界的;其次,流处理中的数据不一定是持久化的,有可能是业务系统实时产生的。这些差异就产生了以下几个重要的影响:

完整数据集只能代表截至目前已经进入到系统中的数据总量。而批处理是对有界的数据集的离线处理;

处理工作是基于事件的,除非明确停止,否则没有“尽头”。流处理系统可以处理无限量的数据。

处理结果立刻可用,并随着新数据的抵达持续更新。批处理是需要等全部数据处理完成后才会返回结果,数据量大,耗费时间很长。

无界和非持久化,导致对流式计算有更高的容错要求

2)流式计算里的状态(State)与容错(fault tolerance)

状态(State)就是计算的中间信息(Intermediate Information);从数据的角度看,流计算的处理方法主要有以下两种:

无状态(Stateless):每一个进入的记录独立于其他记录。不同记录之间没有任何关系,它们可以被独立处理和持久化。例如:map、fliter、静态数据join等操作。

有状态(Stateful):处理进入的记录依赖于之前记录处理的结果。因此,我们需要维护不同数据处理之间的中间信息。每一个进入的记录都可以读取和更新该信息。我们把这个中间信息称作状态(State)。例如:独立键的聚合计数、去重等等。

流计算系统需要一种机制来周期性地持久化相应的状态快照(即checkpoint机制),当计算系统出现异常后,就可以从最近的持久化快照中恢复执行,从而确保计算结果的正确性。对于状态处理,又分为两种:

1、过程状态: 它是流计算的元数据(metadata),用于追踪和记录历史至今,已经被处理的数据偏移量及流处理系统当前的状态。在流的世界中,这些元数据包括 checkpoint /savepoint 以及保存已经处理数据的偏移量(offset)等。这些信息是任何高可靠流处理的基本,同时被无状态和有状态处理需要。

2、数据状态: 这些中间数据来自于数据(被暂时处理过的),它需要在记录之间维护(只在Stateful模式下需要维护)。

3)传统业务系统和流数据处理系统区别

下图是基于DB事务的传统业务系统和基于Flink的流数据处理系统的类比图:

flink 实现数据分析 flink的数据存储在哪_flink_15


如图中所示,两者都是对事件进行响应,并在响应完成后触发相应的行为。但在实际应用中,业务系统的事件往往直接来自用户的实时请求,而数据处理系统的事件则常常是由业务系统所触发。传统业务系统和流数据处理系统的主要差异体现在,前者的计算层和持久化存储层是分开的,计算层从持久化层读写数据;后者的数据和计算都是在本地的(内存或本地磁盘)。而为了达到容错性要求,流计算需要定期将本地状态持久化到外部存储设备。

4)Flink模型

Flink对数据的处理被抽象为以下三步:第一,接受数据;第二,处理数据;第三,输出处理结果。具体来说就是,1,接收(ingest)一个或者多个数据源(hdfs,kafka等);2,执行若干用户需要的转换算子(transformation operators);3,将转换后的结果输出(sink)。

5)数据管道(提取-转换-加载(ETL))

这种类ETL的数据处理管道,是一种在存储系统之间进行数据转换和迁移的方法。就像ETL 作业通常被周期性地触发,将数据从事务型数据库拷贝到分析型数据库或数据仓库一样,Flink里的数据管理也是对输入的数据进行转换、丰富,将其从某个存储系统移动到另一个。但这里的数据管道是以持续流模式运行,而非周期性触发。和周期性 ETL 作业相比,持续数据管道可以明显降低将数据移动到目的端的延迟。很多常见的数据转换和增强操作可以利用 Flink 的 SQL 接口(或 Table API)及用户自定义函数解决。如果数据管道有更高级的需求,可以选择更通用的 DataStream API 来实现。Flink 为多种数据存储系统(如:Kafka、Kinesis、Elasticsearch、JDBC数据库系统等)内置了连接器。同时它还提供了文件系统的连续型数据源及数据汇,可用来监控目录变化和以时间分区的方式写入文件。典型的数据管道应用比如有:电子商务中的实时查询索引构建及持续ETL;下图描述了周期性 ETL 作业和持续数据管道的差异。

flink 实现数据分析 flink的数据存储在哪_big data_16


flink 实现数据分析 flink的数据存储在哪_big data_17

6)Task Slots

每个worker(TaskManager)都是一个JVM进程,可以执行一个或多个子任务(subtask)。任务槽(task slot)就是为了控制一个worker能同时运行多少个任务的(至少一个)。

每个任务槽(task slot)代表TaskManager一个固定的资源子集。比如, 一个TaskManager有3个槽,会将其管理的1/3的内存分给每个槽位。将资源分成不同的槽位意味着一个子任务(subtask)不会跟其他作业的子任务竞争资源,而是会拥有一定量的保留资源。需要注意的是,这里不涉及CPU隔离,目前任务槽仅仅分割task管理的内存。

flink 实现数据分析 flink的数据存储在哪_数据_18

为了适配任务槽(task slot)的数量,用户可以定义子任务(subtask)是如何隔离的。如果每个TaskManager有一个槽,就意味着task组运行在不同的GJVM里。如果每个TaskManager有多个槽意味着多个字任务(subtask)共享同一个JVM。任务在同一个JVM运行可以共享TCP链接和心跳信息。它们可以共享数据集和数据结构,因此可以减少每个任务的开销。默认情况下,Flink 允许 subtask 共享 slot,即便它们是不同的 task 的 subtask,只要是来自于同一作业即可。结果就是一个 slot 可以持有整个作业管道。允许 slot 共享有两个主要优点:

Flink 集群所需的 task slot 和作业中使用的最大并行度恰好一样。无需计算程序总共包含多少个 task(具有不同并行度)。

容易获得更好的资源利用。如果没有 slot 共享,非密集 subtask(source/map())将阻塞和密集型 subtask(window) 一样多的资源。通过 slot 共享,就可以充分利用分配的资源,同时确保繁重的 subtask 在 TaskManager 之间公平分配。

task被JM调度后分布式执行,Flink 将算子的 subtasks 链接成 tasks。每个 task 由一个线程执行。将算子链接成 task 是个有用的优化:它减少线程间切换、缓冲的开销,并且减少延迟的同时增加整体吞吐量。

flink 实现数据分析 flink的数据存储在哪_flink 实现数据分析_19

2.3、Flink的任务执行流程

flink 实现数据分析 flink的数据存储在哪_flink 实现数据分析_20


flink 实现数据分析 flink的数据存储在哪_hadoop_21


flink 实现数据分析 flink的数据存储在哪_数据_22


在Spark的世界观中,一切都是由批次组成的,离线数据是一个大批次,而实时数据是由一个一个无限的小批次组成的。而在Flink的世界观中,在 Flink 中,一切数据都是 Stream,离线数据是有界限的流,实时数据是一个没有界限的流,即所谓的 unbounded (无界)流和 bounded(有界)流。使用过 Hive 或 Mapreduce 或 mysql 的同学应该知道,数据存在 hdfs 或其他文件系统上,并且是一个固定的大小,我们把这些数据称为一批数据。使用过 Spark Streaming 或 Storm 的同学也应该知道数据源源不断的流入,流出,计算,这个过程的数据称为数据流。在 Flink 里,我们把批/流数据全部抽象成流,分为有界的流和无界的流。

无界流:有定义流的开始,但没有定义流的结束。它们会无休止地产生数据。无界流的数据必须持续处理,即数据被摄取后需要立刻处理。我们不能等到所有数据都到达再处理,因为输入是无限的,在任何时候输入都不会完成。处理无界数据通常要求以特定顺序摄取事件,例如事件发生的顺序,以便能够推断结果的完整性。

有界流:有定义流的开始,也有定义流的结束。有界流可以在摄取所有数据后再进行计算。有界流所有数据可以被排序,所以并不需要有序摄取。有界流处理通常被称为批处理。

三、部署配置

部署参考:

flink 实现数据分析 flink的数据存储在哪_big data_23


flink 实现数据分析 flink的数据存储在哪_flink_24

四、运维参考

4.1 密码配置

Flink前端采用nginx,可以使用htpasswd配置页面密码,同样适用于其他场景,执行:

#生成密码
htpasswd -b /app/data/nginx/conf/htpasswd flink 123456 #yum -y  install httpd

#nginx配置密码文件
server {
	listen 8080
	server_name 10.253.2.4;
	location /flink {
		auth_basic "Restricted Access";
		auth_basic_user_file /usr/local/nginx/conf/htpasswd;
		proxy_pass http://172.168.10.6:8081;
	}
}

./nginx -c /opt/nginx/conf/nginx.conf #启动后页面即可

设置登录用户名、密码:打开终端,输入flink安装路径 bin/flink run -e --html5 --host {配置web认证的host地址} --port {监听的端口号} -u {认证的用户名} -p {认证的密码} ;来设置用户名和密码,以登录Apache Flink框架。之后浏览器输入url为http://hostname:port,hostname为配置的host地址,port为配置的监听端口号,点击“登录”,输入刚才设置的用户名和密码,点击“登录”按钮,就可以进入Apache Flink框架的管理界面。

五、应用案例

5.1、Flink + Iceberg 全场景实时数仓的建设实践

参看:https://blog.51cto.com/u_14286418/5323837

六、附录

5.1、Flink 与 Spark对比

产品名称

特性/不同点

相同点

Flink

1)原生的流处理系统

2)提供high level的API,也支持批处理的API;

Master-Slave架构

Spark

未完待续……