Apache Flink fault tolerance源码剖析(五)

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
简介: 上一篇文章我们谈论了保存点的相关内容,其中就谈到了保存点状态的存储。这篇文章我们来探讨用户程序状态的存储,也是在之前的文章中多次提及的state backend(中文暂译为状态终端)。 基于数据流API而编写的程序经常以各种各样的形式保存着状态: 窗口收集/聚合元素(这里的元素可以看作是窗口的状态)直到它们被触发 转换函数可能会使用key/value状态接口来存储数据 转换函数可能实现Checkpointed接口来让它们的本地变量受益于fault tolerant机制 当检查点机制工作时,上面谈到的这些状态将能够基于检查点一同持久化来保证数据不丢失并且得到可持续的恢复。

上一篇文章我们谈论了保存点的相关内容,其中就谈到了保存点状态的存储。这篇文章我们来探讨用户程序状态的存储,也是在之前的文章中多次提及的state backend(中文暂译为状态终端)。

基于数据流API而编写的程序经常以各种各样的形式保存着状态:

  • 窗口收集/聚合元素(这里的元素可以看作是窗口的状态)直到它们被触发
  • 转换函数可能会使用key/value状态接口来存储数据
  • 转换函数可能实现Checkpointed接口来让它们的本地变量受益于fault tolerant机制

当检查点机制工作时,上面谈到的这些状态将能够基于检查点一同持久化来保证数据不丢失并且得到可持续的恢复。那么状态在内部是如何表示及存储的呢?这依赖于状态终端的选择。

我们将从几个方面来分解状态终端的实现:

  • 被支持的状态类型
  • 用户定义的键值对状态
  • 状态快照
  • 状态访问器
  • 状态终端实现

因为状态终端的实现内容较多,所以本文不会太过于拘泥细节,以免管中窥豹

被支持的状态类型

状态相关的接口都维护在package:

org.apache.flink.api.common.state

其继承关系如图:

flink-fault-tolerance-5_state-class-diagram

通过多层的继承,最终的叶子节点是被状态终端直接支持的几种状态类型,它们是:

  • ValueState : 单值状态
  • ListState : 集合状态
  • FoldingState : folding状态,for FoldFunction
  • ReducingState : reducing状态,for ReduceFunction

注意这里只定义了实现这些状态的协议接口,具体的实现本文后面会谈到

针对每一个被直接支持的状态,都有一个描述它们的状态描述符(StateDescriptor),来负责创建对应的状态。一个状态描述符描述状态的名称,默认值。并提供了一个抽象方法来创建状态:

    /**
     * Creates a new {@link State} on the given {@link StateBackend}.
     *
     * @param stateBackend The {@code StateBackend} on which to create the {@link State}.
     */
    public abstract S bind(StateBackend stateBackend) throws Exception;

上面提到的所有被直接支持的状态都有一个描述符:

flink-fault-tolerance-5_state-descriptor

从上面创建状态的方法bind的签名中可以看到,它依赖于参数StateBackend。而StateBackend暂且可以看作是创建状态的代理。

用户定义的键值对状态

上面的State定义了特定状态的接口协议。除了上面的那些基本状态外,Flink还提供了基于键值对的用户定义的状态,它以KvState接口来描述,其实它才是最终结合检查点机制进行存储和恢复的状态表示。其携带多个泛型参数:

  • key的类型
  • 命名空间的类型
  • 最终存储的State的类型
  • 状态描述符StateDescriptor的类型
  • 管理该KvStateAbstractStateBackend的具体类型

可以简单地将其看作State的容器

该接口提供了一个snapshot方法,用于结合检查点机制提供快照支持。并返回KvStateSnapshot的实例来表示一个键值对状态的快照。

KvStateSnapshot<K, N, S, SD, Backend> snapshot(long checkpointId, long timestamp) throws Exception;

当然针对每种被直接支持的状态,都有KvState的特定实现:

flink-fault-tolerance-5_kvstate-class-diagram

状态快照

KvStateSnapshot表示KvState快照的接口,它结合检查点机制提供了对状态进行恢复:

  • restoreState : 基于状态终端以及表示检查点的时间戳等来恢复状态

从类图关系可以看出每个针对键值状态的实现(KvState)都有一个内部类提供与之对应的快照实现:

flink-fault-tolerance-5_kvstatesnapshot-class-diagram

状态访问器

StateHandleoperator提供操作状态的接口,将状态从面向存储介质的原始表示还原为对象表示。重要接口:

T getState(ClassLoader userCodeClassLoader) throws Exception;

可以理解为状态的反序列化接口,根据给定的类加载器加载需要反序列化的类表示来还原状态。

状态终端的实现

所谓的状态终端是真正跟状态持久化介质交互的代理类。

AbstractStateBackend为实现状态终端提供了一个模板。主要提供了如下功能:

  • 状态创建/获取、创建快照
  • 基于检查点存储状态
  • 定义检查点状态输出流

跟检查点有关的部分:

定义了创建状态检查点输出流CheckpointStateOutputView的接口(抽象方法),以及对检查点状态反序列化的接口。这些接口供继承者根据最终的状态终端选择进行实现。

public abstract CheckpointStateOutputStream createCheckpointStateOutputStream(
            long checkpointID, long timestamp) throws Exception;

public abstract <S extends Serializable> StateHandle<S> checkpointStateSerializable(
            S state, long checkpointID, long timestamp) throws Exception;

Flink支持了三种类型的状态终端:

  • MemoryStateBackend
  • FsStateBackend
  • RocksDBStateBackend(第三方开发者实现,本文不进行代码分析)

它们都以AbstractStateBackend为模板:

flink-fault-tolerance-5_AbstractStateBackend-class-diagram

如果没有进行配置,MemoryStateBackend将是默认的实现。

MemoryStateBackend

MemoryStateBackend在内部将数据以对象的形式保存的Java堆中。键值对状态以及窗口operatorhash table的形式存储值、触发器等。

建立在检查点的机制上,该状态终端将对状态进行快照并且将状态的快照作为检查点应答消息的一部分发送给JobManager(master),JobManager将快照存储在它的堆内存中。

MemoryStateBackend的限制:

  • 每个独立状态的大小默认限制在5MB,可以在MemoryStateBackend的构造器中对该值进行增加
  • 不管你将状态大小设置得有多大,它都不能大于akka的frame size
  • 状态的总占用空间必须适配JobManager的内存空间

推荐在如下场景时使用MemoryStateBackend作为状态终端:

  • 本地开发与调试模式
  • 只存储很少状态的Job,例如只包含每次只处理一条记录的函数(MapFlatMapFilter…)的job

FsStateBackend

FsStateBackend采用文件系统URL(包含typeaddresspath)的模式进行配置。例如hdfs://namenode:40010/flink/checkpoints或者file:///data/flink/checkpoints

FsStateBackend将正在处理的数据存储在TaskManager的内存里。结合检查点,它将状态快照写到基于配置的文件系统的文件里。而最小化元数据信息被存储在JobManager的内存里(如果处于高可用模式,元数据将存储在元数据检查点里)。

推荐在如下场景使用FsStateBackend

  • 具有大量状态,很大的窗口,大量键值对状态的Job
  • 全程高可用模式

RocksDBStateBackend

RocksDBStateBackend存储正在处理的数据到RocksDB数据库。而RocksDB被存储在TaskManager的数据字典里。结合检查点机制,整个RocksDB数据库将进行快照并被存储到配置的文件系统中。最小化的元数据被存储到JobManager的内存里(如果配置为高可用模式,将会保存到元数据检查点中)。

推荐在如下场景使用RocksDBStateBackend

  • 具有很大的状态,很长的窗口,大量的键值对状态的Job
  • 全程高可用状态

注意,使用RocksDBStateBackend时,你能保存的状态仅受到磁盘可用空间的限制。因此,与MemoryStateBackend将状态保存在内存中进行对比,这种状态终端允许你保存非常多的状态。但这也意味着,它所能达到的最大化的吞吐量也将不及MemoryStateBackend

综合分析

首先来看具体的状态终端对各种状态的实现:

flink-fault-tolerance-5_statebackend-kvstate

与此对应的KvStateSnapshot也拥有特定的实现:

flink-fault-tolerance-5_statebackend-kvstate-snapshot

结合检查点

状态的存储通常是绑定着检查点的,也就是状态会作为检查点的一部分被一同持久化。因此,它具备了fault tolerance的能力。这里我们分成两部分来看:snapshotrestore

  • snapshot

每个最终的状态,都实现了KvState接口(通过间接继承抽象类AbstractHeapState),而实现该接口就必须实现其snapshot方法。这被认为是所有的最终状态都要实现其生产快照的逻辑。当然,这绝大部分逻辑都被AbstractFsStateAbstractMemState给实现了。

具体而言,AbstractFsState利用FsStateBackend创建FsCheckpointStateOutputStream将状态写入检查点对应的路径下(根据检查点编号)。而AbstractMemState则是将其写入到堆内存中(这里甚至都没有用到检查点编号)。

这里有两个状态终端定义的检查点输出流(用于最终的持久化):

flink-fault-tolerance-5_statebackend-outputstream

  • restore

恢复逻辑分别实现在AbstractFsStateSnapshotAbstractMemStateSnapshotrestoreState方法中。restoreState的逻辑基本是snapshot的反逻辑,将数据从特定的持久化介质中反序列化回来,并生成KvState对象。

小结

本文梳理了状态终端的实现方式,由于内容较多,因此省略了一些细节实现。但从本文的分析应该基本能理清状态终端如何对状态进行持久化以及恢复。



原文发布时间为:2016-06-07


本文作者:vinoYang


本文来自云栖社区合作伙伴CSDN博客,了解相关信息可以关注CSDN博客。

相关实践学习
基于Hologres轻松玩转一站式实时仓库
本场景介绍如何利用阿里云MaxCompute、实时计算Flink和交互式分析服务Hologres开发离线、实时数据融合分析的数据大屏应用。
Linux入门到精通
本套课程是从入门开始的Linux学习课程,适合初学者阅读。由浅入深案例丰富,通俗易懂。主要涉及基础的系统操作以及工作中常用的各种服务软件的应用、部署和优化。即使是零基础的学员,只要能够坚持把所有章节都学完,也一定会受益匪浅。
目录
相关文章
|
2月前
|
存储 人工智能 大数据
The Past, Present and Future of Apache Flink
本文整理自阿里云开源大数据负责人王峰(莫问)在 Flink Forward Asia 2024 上海站主论坛开场的分享,今年正值 Flink 开源项目诞生的第 10 周年,借此时机,王峰回顾了 Flink 在过去 10 年的发展历程以及 Flink社区当前最新的技术成果,最后展望下一个十年 Flink 路向何方。
413 33
The Past, Present and Future of Apache Flink
|
4月前
|
SQL Java API
Apache Flink 2.0-preview released
Apache Flink 社区正积极筹备 Flink 2.0 的发布,这是自 Flink 1.0 发布以来的首个重大更新。Flink 2.0 将引入多项激动人心的功能和改进,包括存算分离状态管理、物化表、批作业自适应执行等,同时也包含了一些不兼容的变更。目前提供的预览版旨在让用户提前尝试新功能并收集反馈,但不建议在生产环境中使用。
1054 13
Apache Flink 2.0-preview released
|
4月前
|
存储 缓存 算法
分布式锁服务深度解析:以Apache Flink的Checkpointing机制为例
【10月更文挑战第7天】在分布式系统中,多个进程或节点可能需要同时访问和操作共享资源。为了确保数据的一致性和系统的稳定性,我们需要一种机制来协调这些进程或节点的访问,避免并发冲突和竞态条件。分布式锁服务正是为此而生的一种解决方案。它通过在网络环境中实现锁机制,确保同一时间只有一个进程或节点能够访问和操作共享资源。
182 3
|
5月前
|
SQL 消息中间件 关系型数据库
Apache Doris Flink Connector 24.0.0 版本正式发布
该版本新增了对 Flink 1.20 的支持,并支持通过 Arrow Flight SQL 高速读取 Doris 中数据。
|
6月前
|
消息中间件 监控 数据挖掘
基于RabbitMQ与Apache Flink构建实时分析系统
【8月更文第28天】本文将介绍如何利用RabbitMQ作为数据源,结合Apache Flink进行实时数据分析。我们将构建一个简单的实时分析系统,该系统能够接收来自不同来源的数据,对数据进行实时处理,并将结果输出到另一个队列或存储系统中。
409 2
|
5月前
|
消息中间件 资源调度 API
Apache Flink 流批融合技术介绍
本文源自阿里云高级研发工程师周云峰在Apache Asia Community OverCode 2024的分享,内容涵盖从“流批一体”到“流批融合”的演进、技术解决方案及社区进展。流批一体已在API、算子和引擎层面实现统一,但用户仍需手动配置作业模式。流批融合旨在通过动态调整优化策略,自动适应不同场景需求。文章详细介绍了如何通过量化指标(如isProcessingBacklog和isInsertOnly)实现这一目标,并展示了针对不同场景的具体优化措施。此外,还概述了社区当前进展及未来规划,包括将优化方案推向Flink社区、动态调整算子流程结构等。
487 31
Apache Flink 流批融合技术介绍
|
4月前
|
分布式计算 监控 大数据
大数据-148 Apache Kudu 从 Flink 下沉数据到 Kudu
大数据-148 Apache Kudu 从 Flink 下沉数据到 Kudu
128 1
|
4月前
|
数据挖掘 物联网 数据处理
深入探讨Apache Flink:实时数据流处理的强大框架
在数据驱动时代,企业需高效处理实时数据流。Apache Flink作为开源流处理框架,以其高性能和灵活性成为首选平台。本文详细介绍Flink的核心特性和应用场景,包括实时流处理、强大的状态管理、灵活的窗口机制及批处理兼容性。无论在实时数据分析、金融服务、物联网还是广告技术领域,Flink均展现出巨大潜力,是企业实时数据处理的理想选择。随着大数据需求增长,Flink将继续在数据处理领域发挥重要作用。
414 0
|
4月前
|
消息中间件 druid Kafka
从Apache Flink到Kafka再到Druid的实时数据传输,用于分析/决策
从Apache Flink到Kafka再到Druid的实时数据传输,用于分析/决策
123 0
|
6月前
|
Java 微服务 Spring
驾驭复杂性:Spring Cloud在微服务构建中的决胜法则
【8月更文挑战第31天】Spring Cloud是在Spring Framework基础上打造的微服务解决方案,提供服务发现、配置管理、消息路由等功能,适用于构建复杂的微服务架构。本文介绍如何利用Spring Cloud搭建微服务,包括Eureka服务发现、Config Server配置管理和Zuul API网关等组件的配置与使用。通过Spring Cloud,可实现快速开发、自动化配置,并提升系统的伸缩性和容错性,尽管仍需面对分布式事务等挑战,但其强大的社区支持有助于解决问题。
111 0

推荐镜像

更多