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

1.1 核心特点

1.1.1 批流一体

所有的数据都天然带有时间的概念,必然发生在某一个时间点。把事件按照时间顺序排列起来,就形成了一个事件流,也叫作数据流。例如信用卡交易事务,传感器收集设备数据、机器日志数据以及网站或移动应用程序上的用户交互行为数据等,所有这些数据都是数据流。

数据时时刻刻都在产生,如同江河奔流不息。例如,每一个人每天都在处理各种各样的事情(事件),解决问题(响应),一年结束之时,人们往往会坐下来总结这一年的得失,并制订新一年的计划。在总结过去的时候,其实就默认给了一个时间范围。再举一个例子,企业进行年终总结时,会统计当年完成了多少业绩,而不是考虑每一笔业务的业绩。由此可以引出两个概念:无界数据(流)、有界数据(批)。

1.无界数据

无界数据是持续产生的数据,所以必须持续地处理无界数据流。数据是无限的,也就无法等待所有输入数据到达后处理,因为输入是无限的,没有终止的时间。处理无界数据通常要求以特定顺序(例如事件发生的顺序)获取,以便判断事件是否完整、有无遗漏。

2.有界数据

有界数据,就是在一个确定的时间范围内的数据流,有开始有结束,一旦确定了就不会再改变。

Flink的设计思想与谷歌Cloud Dataflow的编程模型较为接近,都以流为核心,批是流的特例。Flink擅长处理无界和有界数据。Flink提供的精确的时间控制能力和有状态计算的机制,让它可以轻松应对任何类型的无界数据流,同时Flink还专门设计了算法和数据结构来高效地处理有界数据流。

1.1.2 可靠的容错能力

在分布式系统中,硬件故障、进程异常、应用异常、网络故障等多种多样的异常无处不在。像Flink这样的分布式计算引擎必须能够从故障中恢复到正常状态,以便实现全天候运行。这就要求引擎在故障发生后不仅可以重新启动应用程序,还要确保其内部状态保持一致,从最后一次正确的点重新执行,从用户的角度来说,最终的计算结果与未发生故障是一样的。

1.集群级容错

(1)与集群管理器集成

Flink与集群管理器紧密集成,例如Hadoop YARN、Mesos或Kubernetes。当进程挂掉时,将自动启动一个新进程来接管它的工作。

(2)高可用性设置

Flink具有高可用性模式特性,可消除所有单点故障。HA模式基于Apache ZooKeeper,Zookeeper是一种经过验证的可靠的分布式协调服务。

2.应用级容错

Flink使用轻量级分布式快照机制,设计了检查点(Checkpoint)来实现可靠的容错。其特性如下。

(1)一致性

Flink的恢复机制基于应用程序状态的一致性检查点。如果发生故障,将重新启动应用程序并从最新检查点加载其状态。结合可重放的流数据源,此特性可以保证精确、一次的状态一致性。

Flink、Spark、Storm等都支持引擎内的Exactly-Once语义,即确保数据仅处理一次,不会重复也不会丢失。但是在把结果写入外部存储的时候,可能会发生存储故障、网络中断、Flink应用异常恢复等多种情况,在这些情况下,部分数据可能已经写入外部存储,重复执行可能导致数据的重复写出,此时需要开发者为写出到外部存储的行为保证幂等性。

在Spark、Storm中需要开发者自行实现Sink,实现端到端的Exactly-Once行为。而Flink利用检查点特性,在框架层面提供了Exactly-Once的支持,内置了支持Exactly-Once语义的Sink,即使出现故障,也能保证数据只写出一次。

(2)轻量级

对于长期运行的Flink应用程序,其检查点的状态可能高达TB级,生成和保存检查应用程序的检查点成本非常高。所以Flink提供了检查点的执行异步和增量检查点,以便尽量降低生成和保存检查点带来的计算负荷,避免数据处理的延迟异常变大和吞吐量的短暂剧降。

1.1.3 高吞吐、低延迟

从Storm流计算引擎开始,大家似乎留下了这样一个印象,要实现低延迟,就要牺牲吞吐量,高吞吐、低延迟是流处理引擎的核心矛盾。以Storm为代表的第一代流计算引擎可以做到几十毫秒的处理延迟,但是吞吐量确实不高。后来的Spark Streaming基于mini-batch的流计算框架能够实现较高的吞吐量,但是数据处理的延迟不甚理想,一般可达到秒级。

Flink借助轻量级分布式快照机制,能够定时生成分布式快照,并将快照保存到外部存储中。检查点之间的数据处理被当作是原子的,如果失败,直接回到上一个检查点重新执行即可。在整个数据处理过程中不会产生阻塞,不必像mini-batch机制一样需要等待调度,可以持续处理数据,容错开销非常低。Flink在数据的计算、传输、序列化等方面也做了大量的优化,既能保持数据处理的低延迟,也能尽可能地提高吞吐量。

1.1.4 大规模复杂计算

Flink在设计之初就非常在意性能相关的任务状态和流控等关键技术的设计,这些都使得用Flink执行复杂的大规模任务时性能更胜一筹。

对于大规模复杂计算,尤其是长期运行的流计算应用而言,有状态计算是大数据计算引擎中一个比较大的需求点。所谓的有状态计算就是要结合历史信息进行的计算,例如对于反欺诈行为的识别,要根据用户在近几分钟之内的行为做出判断。一旦出现异常,就需要重新执行流计算任务,但重新处理所有的原始数据是不现实的,而Flink的容错机制和State能够使Flink的流计算作业恢复到近期的一个时间点,从这个时间点开始执行流计算任务,这无疑能够大大降低大规模任务失败恢复的成本。

Flink为了提供有状态计算的性能,针对本地状态访问进行了优化,任务状态始终驻留在内存中,如果状态大小超过可用内存,则保存在高效磁盘上的数据结构中。因此,任务通过访问本地(通常是内存中)状态来执行所有计算,从而达到特别低的处理延迟。Flink通过定期和异步检查点将本地状态进行持久存储来保证在出现故障时实现精确、一次的状态一致性。

Flink的轻量级容错机制也能够尽量降低大规模数据处理时的调度、管理成本,计算规模的增大不会显著增加容错,数据吞吐不会剧烈下降,数据延迟不会急剧增大。

1.1.5 多平台部署

Flink是一个分布式计算系统,需要计算资源才能执行应用程序。Flink可以与所有常见的集群资源管理器(如Hadoop YARN、Apache Mesos和Kubernetes)集成,也可以在物理服务器上作为独立集群运行。

为了实现不同的部署模式,Flink设计了一套资源管理框架,针对上面提到的资源管理平台实现了对应的资源管理器(ResourceManager),能够与上面提到的资源管理平台无缝对接。

部署Flink应用程序时,Flink会根据应用程序配置的并行度自动识别所需资源,并向资源管理器申请资源。如果发生故障,Flink会通过请求新的资源来替换发生故障的资源。Flink提供了提交或控制应用程序的REST接口,方便与外部应用进行集成,管理Flink作业。