Flink内核原理与实现
上QQ阅读APP看书,第一时间看更新

3.1 环境对象

StreamExecutionEnvironment是Flink应用开发时的概念,表示流计算作业的执行环境,是作业开发的入口、数据源接口、生成和转换DataStream的接口、数据Sink的接口、作业配置接口、作业启动执行的入口。

Environment是运行时作业级别的概念,从StreamExecutionEnvironment中的配置信息衍生而来。进入到Flink作业执行的时刻,作业需要的是相关的配置信息,如作业的名称、并行度、作业编号Job ID、监控的Metric、容错的配置信息、IO等,用StreamExecutionRuntime对象就不合适了,很多API是不需要的,所以在Flink中抽象出了Environment作为运行时刻的上下文信息。

RuntimeContext是运行时Task实例级别的概念。Environment本身仍然是比较粗粒度作业级别的配置,对于每一个Task而言,其本身有更细节的配置信息,所以Flink又抽象了RuntimeContext,每一个Task实例有自己的RuntimeContext,RuntimeContext的信息实际上是StreamExecutionEnvironment中配置信息和算子级别信息的综合。

3种环境对象之间的关系如图3-1所示。

图3-1 3种环境对象的关系

对于开发者而言,StreamExecutionEnvironment在作业开发的Main函数中使用,RuntimeContext在UDF开发中使用,Environment则起到衔接StreamExecutionEnvironment和RuntimeContext的作用。

3.1.1 执行环境

执行环境是Flink作业开发、执行的入口,当前版本Flink的批流在API并没有统一,所以有流计算(StreamExecutionEnvironment)和批处理(ExecutionEnvironment)两套执行环境。在本书中,主要介绍流计算应用执行环境。

流计算执行环境体系如图3-2所示。

图3-2 StreamExcecutionEnvironment类体系

StreamExecutionEnvironment是Flink流计算应用的执行环境,是Flink作业开发和启动执行的入口,开发者对StreamExecutionEnvironment的实现是无感知的。

1. LocalStreamEnvironment

本地执行环境,在单个JVM中使用多线程模拟Flink集群。

一般用作本地开发、调试。使用Idea之类的IDE工具,可以比较方便地在代码中设置断点调试和单元测试。如果测试没有问题,就可以提交到真正的生产集群。

其基本的工作流程如下。

1)执行Flink作业的Main函数生成Streamgraph,转化为JobGraph。

2)设置任务运行的配置信息。

3)根据配置信息启动对应的LocalFlinkMiniCluster。

4)根据配置信息和miniCluster生成对应的MiniClusterClient。

5)通过MiniClusterClient提交JobGraph到MiniCluster。

2. RemoteStreamEnvironment

在大规模数据中心中部署的Flink生成集群的执行环境。

当将作业发布到Flink集群的时候,使用RemoteStreamEnvironment。

其基本的工作流程如下:

1)执行Flink作业的Main函数生成Streamgraph,转化为JobGraph。

2)设置任务运行的配置信息。

3)提交JobGraph到远程的Flink集群。

3. StreamContextEnvironment

在Cli命令行或者单元测试时候会被使用,执行步骤同上。

4. StreamPlanEnvironment

在Flink Web UI管理界面中可视化展现Job的时候,专门用来生成执行计划(实际上就是StreamGraph),如图3-3所示。

图3-3 Flink执行计划

5. ScalaShellStreamEnvironment

这是Scala Shell执行环境,可以在命令行中交互式开发Flink作业。

其基本工作流程如下。

1)校验部署模式,目前Scala Shell仅支持attached模式。

2)上传每个作业需要的Jar文件。

其余步骤与RemoteStreamEnvironment类似。

3.1.2 运行时环境

运行时环境在Flink中叫作Environment,是Flink运行时的概念,该接口定义了在运行时刻Task所需要的所有配置信息,包括在静态配置和调度器调度之后生成的动态配置信息。

Environment类体系如图3-4所示。

图3-4 Environment类体系

其有两个实现类RuntimeEnvironment和SavepointEnvironment。

1. RuntimeEnvironment

在Task开始执行时进行初始化,把Task运行相关的信息都封装到该对象中,其中不光包含了配置信息,运行时的各种服务也会被包装到其中,如代码清单3-1所示。

代码清单3-1 Task初始化RuntimeEnvironment

2. SavepointEnvironment

SavepointEnvironment是Environment的最小化实现,在状态处理器的API中使用。Flink1.9版本引入的状态处理器(State Processor)API真正改变了这一现状,实现了对应用程序状态的操作。该功能借助DataSet API扩展了输入和输出格式以读写保存点或检查点数据。由于DataSet和Table API的互通性,用户甚至可以使用关系表API或SQL查询来分析和处理状态数据。

3.1.3 运行时上下文

RuntimeContext是Function运行时的上下文,封装了Function运行时可能需要的所有信息,让Function在运行时能够获取到作业级别的信息,如并行度相关信息、Task名称、执行配置信息(ExecutionConfig)、State等。

Function的每个实例都有一个RuntimeContext对象,在RichFunction中通过getRunctionContext()可以访问该对象。

RuntimeContext的类体系如图3-5所示。

不同的使用场景中有不同的RuntimeContext,具体如下。

1)StreamingRuntimeContext:在流计算UDF中使用的上下文,用来访问作业信息、状态等。

2)DistributedRuntimeUDFContext:由运行时UDF所在的批处理算子创建,在DataSet批处理中使用。

3)RuntimeUDFContext:在批处理应用的UDF中使用。

4)SavepointRuntimeContext:Flink1.9版本引入了一个很重要的状态处理API,这个框架支持对检查点和保存点进行操作,包括读取、变更、写入等。

图3-5 RuntimeContext类体系

5)CepRuntimeContext:CEP复杂事件处理中使用的上下文。

另外,在一些场景中不需要将RuntimeContext中的信息完全暴露,只需要其中某一部分信息,或者需要使用RuntimeContext之外的一些其他信息,这两种情况下,需要对RuntimeContext再进行一次封装。