Apache Flink核心技术解读:纯粹的流式计算引擎
Apache Flink介绍
Apache Flink是近年来越来越流行的开源大型计算机。它同时支持批处理和流处理,还可以用来创建一些基于事件的应用程序。用官网的一句话来介绍Flink就是“Stateful Computations Over Streams”。
首先Flink 是一个纯流计算机。其基本数据模型是数据流。流可以是无边界的无限流,也就是一般意义上的流处理。也可以是有限制的有限流量,也就是批处理。因此,Flink 采用单一架构同时支持流处理和批处理。 其次,Flink 的优势之一就是支持有状态计算。如果一个事件(或一段数据)的处理结果仅与事件本身的内容相关,则称为无状态处理;否则,结果还与之前处理的事件相关,这称为有状态处理。稍微复杂一点的数据处理,比如数据流之间的基本聚合和关联,都是有状态的过程。
![]()
Apache Flink 的基石
Apache Flink 之所以越来越受欢迎,是因为我们认为它与最重要的四个基石密不可分:Checkpoint、State、Time 和 Window。
首先是Checkpoint机制,这是Flink最重要的功能。 Flink基于Chandy-Lamport算法实现分布式一致性快照,从而提供exactly-once语义。 Flink之前的流计算系统(比如Strom、Samza)并没有很好地解决exactly-once问题。在提供一致的语义之后,Flink 引入了托管状态,并提供了 API 接口,让用户在编程时更容易管理状态,感觉像使用 Java。与集合类相同。此外,Flink 还实现了水印机制,解决基于事件时间处理时数据干扰和数据迟到的问题。最后,流计算中的计算通常是基于窗口进行计算的,因此 Flink 提供了一组开箱即用的窗口操作,包括滚动窗口、滑动窗口和会话窗口。它还支持高度灵活的自定义窗口,以满足特定业务的需求。需要。
Flink API历史变迁
![]()
Flink 1.0.0时期增加了State API,即ValueState、ReducingState、ListState等。State API可以说是Flink的一个里程碑式的创新。它允许用户像使用Java集合一样使用Flink State,但可以自动享受状态一致性保证,不会因为错误而丢失状态。后来包含的 Apache Beams State API 也大量借鉴了它。
Flink 1.1.0时期支持Session Window和发送数据容忍功能。
Flink 1.2.0时期提供了ProcessFunction,它是一个更底层的API,用于实现更高级、更复杂的功能。除了能够注册各类状态外,还支持注册定时器(支持EventTime和ProcessingTime),常用于开发一些基于事件、基于时间的应用程序。
Flink 1.3.0时期提供了页面输出功能。运算符的输出通常只有一种输出类型,但有时您可能需要输出不同的类型。比如,除了主流发送出去之外,还想把一些异常数据和迟到的数据以侧流的形式发送出去,发送到下游。在不同的节点进行处理。简而言之,Side Output支持多路输出的功能。
在Flink 1.5.0时期添加了BroadcastState。 BroadcastState 是 State API 的扩展。它用于存储来自上游的广播数据。该算子的每个并发存储的BroadcastState中的数据是完全相同的,因为它是从上游广播的。基于这个条件,我们可以更好的解决CEP中的动态规则功能以及SQL中不相交Join的场景。
Flink 1.6.0时期提供了状态TTL功能和DataStream Interval Join功能。状态 TTL 允许您在请求特定状态时指定生命周期参数 (TTL),并指定系统必须在多长时间内自动清除该状态。在此版本之前,如果用户想要实现这种类型的状态清理,则必须使用 ProcessFunction 注册一个计时器,然后使用计时器的回调来手动清除状态。从这个版本开始,Flink 框架可以基于 TTL 原生解决这个问题。另外,DataStream Interval Join函数也称为Interval Join。例如,对于左流中的每条数据,合并右流前后5分钟内内的数据。这是 5 分钟间隔连接。
Flink High-Level API 历史变化
![]()
在 Flink 1.0.0 时期,存储库中添加了 Table API(结构化数据处理 API)和 CEP(复杂事件处理 API)两个框架,用于第一次。 Table API 是一个结构化的高级 API,支持 Java 和 Scala 语言,类似于 Spark 的 DataFrame API。但当时社区对SQL有很多需求,而且SQL和Table API非常相似。它们都是处理结构化数据的语言,并且在实现上可以共享很多内容。所以在Flink 1.1.0社区基于Apache Calcite重构了整个Table模块,使其同时支持Table API和SQL并共享大部分代码。
在 Flink 1.2.0 时期,社区在 Table API 和 SQL 上支持了丰富的内置窗口操作,包括 Tumbling Window、Sliding Window 和 Session Window。
在Flink 1.3.0时期,社区首先提出了Dynamic Table的概念。借助动态表,流和批可以相互转换。流可以是表,表也可以是流。这是流批关联的基础之一。提现机制是实现动态表的基础。基于Retraction,可以正确实现多级Aggregate和多级Join,保证流式SQL的语义和结果的正确性。另外,该版本还支持CEP算子的可扩展能力(即改变并发)。
Flink 1.5.0时期在Table API和SQL上支持Join操作,包括无限流Join和Winded Join。还添加了 SQL CLI 支持。 SQL CLI 提供了一个类似 shell 的命令对话框,用于交互式执行查询。
Flink Checkpoint & Recovery 历史变化
![]()
Checkpoint 机制在 Flink 早期就已经支持,是 Flink 的核心特性。 Flink 社区也努力提高 Checkpoint 和 Recovery 的效率。
Flink 1.0.0时期提供了RocksDB状态支持。在此版本之前,所有状态数据只能存储在进程的内存中。 JVM 内存具有固定大小。随着数据越来越多,经常出现FullGC和OOM问题,在生产环境中使用起来比较困难。如果你想存储更多的数据和更大的状态,你需要使用RocksDB。 RocksDB是一个基于文件的嵌入式数据库,将数据存储在磁盘上,同时提供高效的读写性能。所以使用RocksDB时不会发生OOM。
Flink 1.1.0时期支持RocksDB Snapshot异步。在之前的版本中,RocksDB的Snapshot过程是同步的,这会阻塞主数据流的处理,极大地影响吞吐量。支持async后,吞吐量得到了很大的提升。
在Flink 1.2.0时期,通过引入KeyGroup机制,支持了KeyedState和OperatorState的可扩展性。即支持改变有状态流计算任务并发数的特性。
Flink 1.3.0时期支持增量检查点机制。 Incemental Checkpoint的支持标志着Flink流计算任务正式进入生产就绪状态。增量检查点只是拍摄该检查点期间新添加的状态的快照并将其永久存储。一般来说,流计算任务、GB级状态甚至TB级状态都是很常见的。如果每次都将整个状态刷新到分布式存储,效率和网络成本会非常高。如果每次只更新新的数据,效率会高很多。该版本还引入了细粒度提取功能。做细粒度恢复时,只需要恢复故障节点的连通子图,而不是整个作业,可以提高恢复效率。
Flink 1.5.0时期引入了本地状态恢复机制。因为基于检查点机制,状态会持久存储在HDFS等分布式存储中。当发生故障转移时,必须重新从外部HDFS下载数据。如果条件特别大,下载时间会更长。如果时间较长,则从故障转移恢复所需的时间也会较长。本地状态恢复机制会提前在本地备份状态文件。当作业失败时,可以直接在本地恢复,无需从远程HDFS重新下载状态文件,提高恢复效率。
Flink运行时的历史变化
![]()
在Flink 1.2.0时期,提供了Async I/O功能。异步 I/O 是阿里巴巴向社区贡献的一项备受期待的功能。其主要目的是解决与外部系统交互时成为系统瓶颈的网络延迟问题。例如,要关联某些字段,必须查询外部 HBase 表。同步方式是每次查询操作都会被阻塞,频繁的I/O请求会导致数据流被卡住。使用异步I/O时,可以同时发起N个异步查询请求,而不会阻塞主数据流,从而提高整个作业的吞吐量,提高CPU利用率。
Flink 1.3.0时期引入了HistoryServer模块。 HistoryServer的主要功能是在作业完成后将作业的状态和信息归档,以便后续开发人员可以进行一些深入的研究。
在Flink 1.4.0时期只提供了一次端到端的语义保证。 Exactly-once 意味着每个输入只会应用于最终结果一次且仅一次。即使出现软件或硬件错误,也不会丢失数据或重复计算。在此版本之前,一次性保修的范围仅限于 Flink 应用程序本身,不包括发送到外部系统的部分。在故障转移期间,可能会向外部系统写入重复的数据,因此通常使用幂等外部系统来解决此问题。在 Flink 1.4 版本中,Flink 基于两阶段提交协议实现了语义端到端的恰好一次保证。内置支持 Kafka 的端到端保证,为自定义外部存储提供TwoPhaseCommitSinkFunction 实现端到端的一次性保证。
在Flink 1.5.0时期,Flink发布了新的分发模型和处理模型(FLIP6)。新的分销模式的发展已经持续了很长时间。该模型的实现显着改变了Flink的核心代码。可以说是自 Flink 项目创建以来运行时最大的变化。总之,新模型可以更好地在YARN和MESOS调度系统上动态分配资源和动态释放资源,实现更高的资源利用率并提供作业之间更好的隔离。
除了FLIP6的改进之外,该版本还对网站堆栈进行了重构。重构的原因是旧版本中多个上下游任务之间的通信将共享同一个TCP连接。当特定任务发生背压时,共享该连接的所有任务都将被阻塞。反压的粒度是TCP连接级别。为了完善背压机制,Flink 采用了基于 Credit 的流控,这是解决网络拥塞的经典流控方法。将流控粒度细化到具体任务级别,有效缓解背压对吞吐量的影响。
总结
Flink 同时支持流处理和批处理。目前的功率计算模型已经比较成熟和领先,也得到了各公司量产验证。社区未来将持续提升流计算的性能和功能,包括扩展Flink SQL,提供更丰富的功能,引入更多的优化。另一方面,也会加大批处理、机器学习等生态能力的提升力度。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网