Apache Flink

Apache Flink论文简读

Apache Flink™: Stream and Batch Processing in a Single Engine

Flink不同于Spark的batch processing,它着眼于data streaming processing。它的输入可被看做一条无穷的stream,将函数应用到stream上,再输出。Flink底层是流式处理,延迟更小,但是在某些时候batch processing可能更有效,因此Flink在上层也基于流式处理构建了batch处理,它通过记录流式处理的start point,以及维护流式运行过程中的state来实现一个窗口的batch处理。

batch处理与流式处理的异同

  1. batch看到是一个dataset,它可认为是一堆无序的records集合,然后将算法应用到dataset上面。Spark采用的内存型的RDD,然后将其划分成一个个的小的batch,Schedule这些batch到不同的机器上执行。Spark的batch处理过程可看做一个有向无环图,在多轮iteration的过程中,会不断的schedule job,会有一定的处理时延。
  2. 流式处理看到的是一条具有无限输入的记录流,与batch不同的是,它的输入有序,并有时间戳的概念。Flink在这个数据流上应用算法处理数据,延迟很低;在有batch需求的场景下,可通过设置流处理起始点,并记录处理状态,更新状态,来实现batch处理。此外,Flink有一个专门设计的API来支持static datasets,它使用专门的数据结构和算法,往往更高效。

Flink基础软件栈架构

Apache Flink_第1张图片
  1. 软件栈

    如上面图1所示,Flink Core底层是流处理引擎,然后在上层抽象出Batch processing和Stream
    Processing,再上层构建几种常用的应用:表格,图,机器学习,复杂事件处理等

  2. 流处理模型

    客户端接收程序代码,转换成data-flow graph,然后提交给Job Manager。Job Manager将job分发给Task manager并跟踪状态和执行结果,发生失败的failover等等。

上层的任何代码都最终会被编译成data-flow graph,然后交给Flink的Core层来统一处理。

Flink底层数据流图

数据流图是上层各种API的底层抽象,被Core层所执行,它主要包括两种结构实体:有状态的Operators以及Data Streams。当前层的Operator接收上一层的Operator的输出作为输入,并将运算结果以流的形式传递到下一层的Operator,Data Stream是连接两个Operator的通道。

基本结构

Apache Flink_第2张图片
如上图所示,OP1这个运算符接收SRC1的输出,并将运算结果传递到下一层的Operator SNK1。这三个Operator由两个data stream进行连接,分别是IS1和IS3。这两个数据流有所不同,IS1是一种暂时性的中间结果,这意味着我们不需要将其序列化到非易失性存储实体中(内存中暂存即可),这就为Pipeline的处理提供了可能,SRC1和OP1可以并行运行,上层处理一个record之后,可以直接传递到下层继续处理,组成一个pipeline的模式;而IS3是需要将流序列化到非易失性存储的数据流,这种意味着OP1必须首先将输出序列化到磁盘中,SNK1才能启动执行,这样两边的Operator就不能并行运行,同时还有额外的磁盘I/O的开销,这种流叫作blocking data stream。blocking data stream要求生产者必须生产一定量的数据之后,才能用于下层的消费,它会先将积累的records存储到内存中,如果内存不够,那就序列化到磁盘中。

数据交换的时延和吞吐

两个Operator通过交换buffer的方式来交换数据,buffer在两种情况下传递到下层的消费者:(a) buffer满了, (b) 超时了。 如果超时时间比较短或者buffer比较小,那么延迟会很低,但是这样的话吞吐量会下降,通过调整超时时间或者buffer的大小,可以调整throughout和latency的tradeoff。

控制事件与records的融合

值得注意的是,Flink在records中间可以自由的插入Control Event,operator在收到相应的event进行相应的处理,这使得控制事件可以与现有的流直接融合,举例如下三种控制事件:

  1. checkpoint barriers

    这种控制事件用于Fault tolerance。在流中插入checkpoint事件,会促使流将当前的状态保存下来,当发生故障后,可以直接使用上一次的checkpoint来恢复。

  2. watermarks

    这种控制事件标识records的处理状态。我们知道records有两种时间概念:event-time和processing-time,在延迟很大时,这两个指标可能相差很大。为了控制差异,可以插入watermarks,并绑定一个时间属性t,例如如果operator如果收到了一个event-time为t的watermarks,意味着所有event-time小于t的records全都进入了operator中。这种机制在window records处理特别有效,例如5s一个windows,在5s结束之后插入一个watermark,来指示operator处理这个完整的windows。

  3. iteration barriers

    这个专门的barrier是用于像机器学习这种需要多轮iteration的场景。传统的Spark在iteration中,必须通过schedule a new job,这无疑会浪费大量的系统。很多场景下,迭代过程应该是一个自循环的过程:接收外部输入,内部多轮迭代,传递到下层输出。

下图是一个简单的迭代处理框架,operator内部包含了核心的处理逻辑。

Apache Flink_第3张图片

Flink上层分析框架

有状态的流处理

很多上层应用需要状态管理,例如session处理,图处理,机器学习(例如一颗训练好的决策树)等。Flink提供了接口来bind operator和相应的状态,另外用户还可以指定这些状态在后端存储,以用于故障恢复。

流窗口

这种主要用于时间段内分析,很多分析操作需要对窗口获取一些统计信息。Flink使用windows的assigned(用于record分配到哪个窗口), trigger(用于指定窗口啥时候执行),retain(用于指定窗口多少内容保留到下一次)。下面是一个代码的例子,它定义了一个全局window,每1000次触发一次窗口执行,并且每次保留100个records,用于下次的窗口。

stream
.window(GlobalWindow.create())
.trigger(Count.of(1000))
.evict(Count.of(100))
  • [1] Apache Flink™: Stream and Batch Processing in a Single Engine

你可能感兴趣的:(分布式系统)