Apache Flink fault tolerance源码剖析(三)

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
任务调度 XXL-JOB 版免费试用,400 元额度,开发版规格
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 上一篇文章我们探讨了基于定时任务的周期性检查点触发机制以及基于Akka的actor模型的消息驱动协同机制。这篇文章我们将探讨Zookeeper在Flink的Fault Tolerance所起到的作用。

上一篇文章我们探讨了基于定时任务的周期性检查点触发机制以及基于Akka的actor模型的消息驱动协同机制。这篇文章我们将探讨Zookeeper在Flink的Fault Tolerance所起到的作用。

其实,Flink引入Zookeeper的目的主要是让JobManager实现高可用(leader选举)。

因为Zookeeper在Flink里存在多种应用场景,本篇我们还是将重心放在Fault Tolerance上,即讲解Zookeeper在检查点的恢复机制上发挥的作用。

如果用一幅图表示快照机制(检查点)大致的流程可见下图:

flink-fault-tolerance-3-overview

跟本文相关的主要有4,5,6三步

两种恢复模式

因为跟本文切实相关,所以先介绍一下JobManagerRecoveryMode(恢复模式)。RecoveryMode作为一个枚举类型,它有两个枚举值:

  • STANDALONE
  • ZOOKEEPER

STANDALONE表示不对JobManager的失败进行恢复。而ZOOKEEPER表示JobManager将基于Zookeeper实现HA(高可用)。

两种类型的检查点

在前面的文章中已经提及过Flink里的检查点分为两种:PendingCheckpoint(正在处理的检查点)和CompletedCheckpoint(完成了的检查点)。

PendingCheckpoint表示一个检查点已经被创建,但还没有得到所有该应答的task的应答。一旦所有的task都给予应答,那么它将会被转化为一个CompletedCheckpointPendingCheckpoint通过toCompletedCheckpoint实例方法来将其转化为已完成了的检查点。其核心实现如下:

if (notYetAcknowledgedTasks.isEmpty()) {
    CompletedCheckpoint completed =  new CompletedCheckpoint(jobId, checkpointId,checkpointTimestamp, System.currentTimeMillis(), new ArrayList<StateForTask>(collectedStates));
    dispose(null, false);           
    return completed;
}

它会检查还没有ack该检查点的task集合,如果集合为空(即所有task都已应答),则基于当前实例的属性构建一个CompletedCheckpoint的实例,并最终返回新创建的实例。但在返回之前,调用了dispose进行资源释放。

这个dispose方法是一个私有方法,其内部实现依赖于releaseState这个flag,上面的dispose调用将其置为false,意为不释放task状态:

if (releaseState) {
    for (StateForTask state : collectedStates) {
        state.discard(userClassLoader);
    }
}

但最终,collectedStates这个集合总是会被清空:

collectedStates.clear();
notYetAcknowledgedTasks.clear();

toCompletedCheckpoint方法为什么不释放task的状态呢,因为它的语义只是提供转化操作,其实collectedStates这个集合已经在构造CompletedCheckpoint时被深拷贝给CompletedCheckpoint的实例了。而这些task的状态其最终的释放,将会由CompletedCheckpointdiscard方法完成。

PendingCheckpoint的公共的discard方法的实现就会直接释放收集的状态集合:

public void discard(ClassLoader userClassLoader) {
    dispose(userClassLoader, true);
}

公共的discard方法常用于检查点超时回收以及当最新的检查点已经完成时,距离当前时间更久的未完成的检查点的自动失效

CompletedCheckpoint表示一个已经成功完成了得检查点,当一个检查点在得到所有要求的task的应答之后被认为是一个已完成的检查点。

已完成的检查点的存储

根据JobManager的恢复模式,Flink提供了两种已完成的检查点的存储机制的实现:

  • StandaloneCompletedCheckpointStore
  • ZooKeeperCompletedCheckpointStore

他们都实现了接口CompletedCheckpointStore,这个接口提供了思个值得关注的方法:

  • recover :用于恢复可访问的检查点CompletedCheckpoint的实例
  • addCheckpoint :将已完成的检查点加入到检查点集合
  • getLatestCheckpoint :获得最新的检查点
  • discardAllCheckpoints : 回收所有的已完成的检查点

针对RecoveryModeSTANDALONE提供了StandaloneCompletedCheckpointStore。它提供了一个基于JVM堆内存的ArrayDeque来存放检查点。

而针对RecoveryModeZOOKEEPER提供的ZooKeeperCompletedCheckpointStore要复杂得多。这也是我们关注的重点。它的实现依赖于两个存储机制:

在Zookeeper中的分布式存储:

private final ZooKeeperStateHandleStore<CompletedCheckpoint> checkpointsInZooKeeper;

本地JVM内存中的存储:

private final ArrayDeque<Tuple2<StateHandle<CompletedCheckpoint>, String>> checkpointStateHandles;

我们先来看恢复方法recover,恢复的过程首先是从Zookeeper获取所有的检查点,这里为了规避并发修改带来的失败,采用了循环重试的机制:

        while (true) {
            try {
                initialCheckpoints = checkpointsInZooKeeper.getAllSortedByName();
                break;
            }
            catch (ConcurrentModificationException e) {
                LOG.warn("Concurrent modification while reading from ZooKeeper. Retrying.");
            }
        }

在恢复时,将从Zookeeper中读取最新的检查点,如果检查点超过一个,仅仅最新的那个检查点有效,旧的都会被丢弃。如果存在着网络分区,多个JobManager的实例并发对相同的程序实行检查点,那么选择任意一个验证通过的已完成的检查点都是没有问题的。

        if (numberOfInitialCheckpoints > 0) {
            // Take the last one. This is the latest checkpoints, because path names are strictly
            // increasing (checkpoint ID).
            Tuple2<StateHandle<CompletedCheckpoint>, String> latest = initialCheckpoints
                    .get(numberOfInitialCheckpoints - 1);

            CompletedCheckpoint latestCheckpoint = latest.f0.getState(userClassLoader);

            checkpointStateHandles.add(latest);

            LOG.info("Initialized with {}. Removing all older checkpoints.", latestCheckpoint);

            for (int i = 0; i < numberOfInitialCheckpoints - 1; i++) {
                try {
                    removeFromZooKeeperAndDiscardCheckpoint(initialCheckpoints.get(i));
                }
                catch (Exception e) {
                    LOG.error("Failed to discard checkpoint", e);
                }
            }
        }

discardAllCheckpoints方法会做四件事:

  • 迭代每个检查点,将其从Zookeeper中移除
  • discard每个已完成的检查点
  • discard每个存储的状态
  • 将本地集合清空掉

检查点编号计数器

每个检查点都有各自的编号,为Long类型。根据JobManager的恢复模式分别提供了两种计数器:

  • StandaloneCheckpointIDCounter
  • ZooKeeperCheckpointIDCounter

计数器在这里被认为是一种服务,它具备startstop方法

StandaloneCheckpointIDCounter 只是简单得对 AtomicLong进行了包装,因为在这种模式下,JobManager几乎是不可恢复的,所以这么做就足够了。

ZooKeeperCheckpointIDCounter是基于Zookeeper实现的一种分布式原子累加器。具体的做法是每一个计数器,在Zookeeper上新建一个ZNode,形如:

/flink/checkpoint-counter/<job-id> 1 [persistent]
....
/flink/checkpoint-counter/<job-id> N [persistent]

在Zookeeper中的检查点编号被要求是升序的,这可以使得我们在JobManager失效的情况下,可以拥有一个共享的跨JobManager实例的计数器。

值得一提的是,这里使用的Zookeeper的客户端是CuratorFramework,同时还利用了它附带的SharedCount这一recipes来作为分布式共享的计数器。

而在累加接口方法getAndIncrement的实现上,使用了循环尝试的机制:

    public long getAndIncrement() throws Exception {
        while (true) {
            ConnectionState connState = connStateListener.getLastState();

            if (connState != null) {
                throw new IllegalStateException("Connection state: " + connState);
            }

            VersionedValue<Integer> current = sharedCount.getVersionedValue();

            Integer newCount = current.getValue() + 1;

            if (sharedCount.trySetCount(current, newCount)) {
                return current.getValue();
            }
        }
    }

另外从stop方法的实现来看,如果一个计数器停止,则会再Zookeeper中删除其对应的ZNode

检查点恢复服务

所谓的检查点恢复服务,其实就是聚合了上面的已完成的检查点存储以及检查点编号计数器这两个功能。因为Flink提供了STANDALONE以及ZOOKEEPER这两个恢复模式,所以这里存在一个基于不同模式创建服务的工厂接口CheckpointRecoveryFactory。并针对这两种恢复模式分别提供了两个工厂:StandaloneCheckpointRecoveryFactory以及ZooKeeperCheckpointRecoveryFactory

具体的功能聚合体现在这两个方法上:

    /**
     * Creates a {@link CompletedCheckpointStore} instance for a job.
     *
     * @param jobId           Job ID to recover checkpoints for
     * @param userClassLoader User code class loader of the job
     * @return {@link CompletedCheckpointStore} instance for the job
     */
    CompletedCheckpointStore createCompletedCheckpoints(JobID jobId, ClassLoader userClassLoader)
            throws Exception;

    /**
     * Creates a {@link CheckpointIDCounter} instance for a job.
     *
     * @param jobId Job ID to recover checkpoints for
     * @return {@link CheckpointIDCounter} instance for the job
     */
    CheckpointIDCounter createCheckpointIDCounter(JobID jobId) throws Exception;

两个工厂的具体实现并没有什么特别的地方。检查点恢复服务会被JobManager使用到。

小结

本篇文章我们主要分析了,Zookeeper在Flink的Fault Tolerance机制中发挥的作用。但因为Zookeeper在Flink中得主要用途是实现JobManager的高可用,所以里面的部分内容多少还是跟这一主题有所联系。




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


本文作者: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
|
4月前
|
分布式计算 监控 大数据
大数据-148 Apache Kudu 从 Flink 下沉数据到 Kudu
大数据-148 Apache Kudu 从 Flink 下沉数据到 Kudu
128 1
|
4月前
|
数据挖掘 物联网 数据处理
深入探讨Apache Flink:实时数据流处理的强大框架
在数据驱动时代,企业需高效处理实时数据流。Apache Flink作为开源流处理框架,以其高性能和灵活性成为首选平台。本文详细介绍Flink的核心特性和应用场景,包括实时流处理、强大的状态管理、灵活的窗口机制及批处理兼容性。无论在实时数据分析、金融服务、物联网还是广告技术领域,Flink均展现出巨大潜力,是企业实时数据处理的理想选择。随着大数据需求增长,Flink将继续在数据处理领域发挥重要作用。
414 0
|
5月前
|
运维 数据处理 数据安全/隐私保护
阿里云实时计算Flink版测评报告
该测评报告详细介绍了阿里云实时计算Flink版在用户行为分析与标签画像中的应用实践,展示了其毫秒级的数据处理能力和高效的开发流程。报告还全面评测了该服务在稳定性、性能、开发运维及安全性方面的卓越表现,并对比自建Flink集群的优势。最后,报告评估了其成本效益,强调了其灵活扩展性和高投资回报率,适合各类实时数据处理需求。
|
3月前
|
存储 分布式计算 流计算
实时计算 Flash – 兼容 Flink 的新一代向量化流计算引擎
本文介绍了阿里云开源大数据团队在实时计算领域的最新成果——向量化流计算引擎Flash。文章主要内容包括:Apache Flink 成为业界流计算标准、Flash 核心技术解读、性能测试数据以及在阿里巴巴集团的落地效果。Flash 是一款完全兼容 Apache Flink 的新一代流计算引擎,通过向量化技术和 C++ 实现,大幅提升了性能和成本效益。
1808 73
实时计算 Flash – 兼容 Flink 的新一代向量化流计算引擎
|
1月前
|
消息中间件 关系型数据库 MySQL
Flink CDC 在阿里云实时计算Flink版的云上实践
本文整理自阿里云高级开发工程师阮航在Flink Forward Asia 2024的分享,重点介绍了Flink CDC与实时计算Flink的集成、CDC YAML的核心功能及应用场景。主要内容包括:Flink CDC的发展及其在流批数据处理中的作用;CDC YAML支持的同步链路、Transform和Route功能、丰富的监控指标;典型应用场景如整库同步、Binlog原始数据同步、分库分表同步等;并通过两个Demo展示了MySQL整库同步到Paimon和Binlog同步到Kafka的过程。最后,介绍了未来规划,如脏数据处理、数据限流及扩展数据源支持。
208 0
Flink CDC 在阿里云实时计算Flink版的云上实践
zdl
|
3月前
|
消息中间件 运维 大数据
大数据实时计算产品的对比测评:实时计算Flink版 VS 自建Flink集群
本文介绍了实时计算Flink版与自建Flink集群的对比,涵盖部署成本、性能表现、易用性和企业级能力等方面。实时计算Flink版作为全托管服务,显著降低了运维成本,提供了强大的集成能力和弹性扩展,特别适合中小型团队和业务波动大的场景。文中还提出了改进建议,并探讨了与其他产品的联动可能性。总结指出,实时计算Flink版在简化运维、降低成本和提升易用性方面表现出色,是大数据实时计算的优选方案。
zdl
220 56
|
2月前
|
存储 关系型数据库 BI
实时计算UniFlow:Flink+Paimon构建流批一体实时湖仓
实时计算架构中,传统湖仓架构在数据流量管控和应用场景支持上表现良好,但在实际运营中常忽略细节,导致新问题。为解决这些问题,提出了流批一体的实时计算湖仓架构——UniFlow。该架构通过统一的流批计算引擎、存储格式(如Paimon)和Flink CDC工具,简化开发流程,降低成本,并确保数据一致性和实时性。UniFlow还引入了Flink Materialized Table,实现了声明式ETL,优化了调度和执行模式,使用户能灵活调整新鲜度与成本。最终,UniFlow不仅提高了开发和运维效率,还提供了更实时的数据支持,满足业务决策需求。

热门文章

最新文章

推荐镜像

更多