2.3 编程模型
2.3.1 分层组件栈
Flink的组件分为4层,各个模块之间的层次关系如图2-5所示。
图2-5 Flink各个模块之间的层次关系
(1)Deploy层:Flink支持多种部署模式,如本地(Local)单机版、Standalone集群、YARN集群及云(Cloud)部署模式。
(2)Core 层:本层是 Flink 分布式数据处理引擎的核心实现层,包括计算图的所有底层实现,例如时间与窗口机制、一致性语义、任务管理与调度、物理执行计划。应用程序通常不需要调用本层 API,而是调用流处理 API、批处理API或构建在这两层API基础之上的Library API。
(3)API层:该层包括流处理API和批处理API,Flink的批处理是建立在流式架构上的,而不是用批处理模拟流处理,这种技术基因决定了 Flink 更适用于流处理的场合。
(4)Library层:该层是Flink的应用框架层,构建在流处理API和批处理API之上,因此同一应用框架库有两种版本选择,如流式关系型 API(Table/SQL)。此外,本层还包括CEP、FlinkML和Gelly。
2.3.2 流式计算模型
一个典型的流处理应用程序(命名为Programm 2.1)如下:
这段程序的逻辑计算图形式如图2-6所示。
图2-6 Programm 2.1的逻辑计算图形式
图 2-6 中 Stream 为传输通道中的数据,Operator 为计算图的节点,Streaming Dataflow为计算图。
计算图的物理形式由计算节点的多个并行实例组成,其中并行实例的含义是:在分布式环境中,同一计算节点有多个功能相同的物理部署实例,如图2-7中逻辑形式中的map()节点会有两个部署实例map()[1]和map()[2]。
在并行模式时:
(1)每个Operator的实例数为并行度,任意两个Operator的并行度之间是独立的。例如,图2-7中Source Operator的并行度为2,而Sink Operator的并行度为1;每个Operator称为一个任务,Operator的每个实例称为子任务(subtask),子任务这个概念来自其和JVM线程之间的关系。
图2-7 Programm 2.1的物理计算图形式
(2)Stream有一个或多个分区(partition)。Stream有两种模式:
● 直连(One-to-One)模式,即一个实例的输出是另一个实例的输入。在Programm 2.1 的物理计算图形式中,Source 的 subtask[1](即 Source[1])和map的subtask[1](即map [1])直接相连,Source[1]的输出全部传输给map [1],没有被拆分成多个分区。
● 分区(Redistribution)模式,即一个实例的输出被拆分成多个部分传输给多个下级实例。在Programm 2.1的物理计算图形式中,map [1]被拆分成两部分,分别输入给不同的下级实例。
2.3.3 流处理编程
1.DataStream与DataSet
Flink用DataStream表示无界数据集,用DataSet表示有界数据集,前者用于流处理应用程序,后者用于批处理程序。根据所处理事件数据结构类型的不同,应用程序可以定义不同类型的 DataStream对象和 DataSet对象。以下程序定义事件类型为String的DataStream对象和事件类型为LabeledVector(带标签的训练样本,每个样本用向量表示)的DataSet对象:
从操作形式上看,DataStream 和 DataSet 与集合(Collection)有些相似,但是两者有着本质不同:
(1)DataStream 和 DataSet 是不可变的数据集合,因此不可以像操纵集合那样增加或删除 DataStream和 DataSet中的元素,也不可以通过诸如下标等方式访问某个元素。这里重申之前定义的概念,事件、元素、数据等都是用于指代流处理或批处理所处理的数据对象的,具体使用哪个称呼依赖语境。
(2)Flink应用程序通过Source创建DataStream对象和DataSet对象,通过转换操作产生新的DataStream对象和DataSet对象。
2.程序结构
Flink按照数据处理流程编写应用程序,共分为5个步骤。
1)获取运行时
运行时分为两类:StreamingExecutionEnvironment和ExecutionEnvironment,分别对应流处理和批处理程序:
运行时是应用程序被调度执行时的上下文环境,上述方法根据当前环境自动选择本地或集群运行时环境。以流处理为例,创建方法如下:
(1)通过createLocalEnvironment方法创建运行时,基于这种运行时的应用程序会运行在同一个 JVM 进程中,本地调试时通常采用这种运行时。createLocalEnvironment有三种接口形式:
从上面的接口可以看出,通过 createLocalEnvironment 方法创建的运行仍是StreamingExecutionEnvironment。
(2)通过 createRemoteEnvironment 创建运行时,基于这种运行时的应用程序会被提交到集群中运行,连接集群调试通常用这种运行时。createRemoteEnvironment有两种接口形式:
2)添加外部数据源
可以添加外部数据源,如 Kafka和文件,也可以由应用创建 DataStream或DataSet,后一种方法常用于测试环境。
3)定义算子转换函数
下面的代码将input元素值转换成整型,转换后得到DataStream[Int]:
4)定义Sink
Sink的功能是将数据处理结果写入外部系统:
除了上述两种常用的Sink,应用程序还可以将处理结果写入Kafka:
5)启动程序
调用运行时的execute()方法:
3.指定键(key)
可以通过Scala Case类(或Java元组)的位置索引、对象属性名称、key的选择器(selector)三种方式指定key,定义如下:
4.并行度设置
有4种设置Flink并行度的方式。
(1)通过紧跟在Operator之后的setParallelism方法设置并行度,这种并行度只影响对应的Operator:
(2)通过运行时设置作业级并行度:
(3)通过客户端设置并行度,这种并行度也是作业级的:
(4)通过 Flink 的配置文件设置系统级并行度,这种并行度对集群上的所有作业都起作用: