写点什么

Flink Checkpoint 问题排查实用指南

  • 2019-09-19
  • 本文字数:5312 字

    阅读完需:约 17 分钟

Flink Checkpoint问题排查实用指南

在 Flink 中,状态可靠性保证由 Checkpoint 支持,当作业出现 failover 的情况下,Flink 会从最近成功的 Checkpoint 恢复。在实际情况中,我们可能会遇到 Checkpoint 失败,或者 Checkpoint 慢的情况,本文会统一聊一聊 Flink 中 Checkpoint 异常的情况(包括失败和慢),以及可能的原因和排查思路。

1. Checkpoint 流程简介

首先我们需要了解 Flink 中 Checkpoint 的整个流程是怎样的,在了解整个流程之后,我们才能在出问题的时候,更好的进行定位分析。



从上图我们可以知道,Flink 的 Checkpoint 包括如下几个部分:


  • JM trigger checkpoint

  • Source 收到 trigger checkpoint 的 PRC,自己开始做 snapshot,并往下游发送 barrier

  • 下游接收 barrier(需要 barrier 都到齐才会开始做 checkpoint)

  • Task 开始同步阶段 snapshot

  • Task 开始异步阶段 snapshot

  • Task snapshot 完成,汇报给 JM


上面的任何一个步骤不成功,整个 checkpoint 都会失败。

2 Checkpoint 异常情况排查

2.1 Checkpoint 失败

可以在 Checkpoint 界面看到如下图所示,下图中 Checkpoint 10423 失败了。



点击 Checkpoint 10423 的详情,我们可以看到类系下图所示的表格(下图中将 operator 名字截取掉了)。



上图中我们看到三行,表示三个 operator,其中每一列的含义分别如下:


  • 其中 Acknowledged 一列表示有多少个 subtask 对这个 Checkpoint 进行了 ack,从图中我们可以知道第三个 operator 总共有 5 个 subtask,但是只有 4 个进行了 ack;

  • 第二列 Latest Acknowledgement 表示该 operator 的所有 subtask 最后 ack 的时间;

  • End to End Duration 表示整个 operator 的所有 subtask 中完成 snapshot 的最长时间;

  • State Size 表示当前 Checkpoint 的 state 大小 – 主要这里如果是增量 checkpoint 的话,则表示增量大小;

  • Buffered During Alignment 表示在 barrier 对齐阶段积攒了多少数据,如果这个数据过大也间接表示对齐比较慢);


Checkpoint 失败大致分为两种情况:Checkpoint Decline 和 Checkpoint Expire。

2.1.1 Checkpoint Decline

我们能从 jobmanager.log 中看到类似下面的日志


Decline checkpoint 10423 by task 0b60f08bf8984085b59f8d9bc74ce2e1 of job 85d268e6fbc19411185f7e4868a44178. 其中


10423 是 checkpointID,0b60f08bf8984085b59f8d9bc74ce2e1 是 execution id,85d268e6fbc19411185f7e4868a44178 是 job id,我们可以在 jobmanager.log 中查找 execution id,找到被调度到哪个 taskmanager 上,类似如下所示:


2019-09-02 16:26:20,972 INFO  [jobmanager-future-thread-61] org.apache.flink.runtime.executiongraph.ExecutionGraph        - XXXXXXXXXXX (100/289) (87b751b1fd90e32af55f02bb2f9a9892) switched from SCHEDULED to DEPLOYING.2019-09-02 16:26:20,972 INFO  [jobmanager-future-thread-61] org.apache.flink.runtime.executiongraph.ExecutionGraph        - Deploying XXXXXXXXXXX (100/289) (attempt #0) to slot container_e24_1566836790522_8088_04_013155_1 on hostnameABCDE
复制代码


从上面的日志我们知道该 execution 被调度到 hostnameABCDEcontainer_e24_1566836790522_8088_04_013155_1 slot 上,接下来我们就可以到 container container_e24_1566836790522_8088_04_013155 的 taskmanager.log 中查找 Checkpoint 失败的具体原因了。


另外对于 Checkpoint Decline 的情况,有一种情况我们在这里单独抽取出来进行介绍:Checkpoint Cancel。


当前 Flink 中如果较小的 Checkpoint 还没有对齐的情况下,收到了更大的 Checkpoint,则会把较小的 Checkpoint 给取消掉。我们可以看到类似下面的日志:


$taskNameWithSubTaskAndID: Received checkpoint barrier for checkpoint 20 before completing current checkpoint 19. Skipping current checkpoint.
复制代码


这个日志表示,当前 Checkpoint 19 还在对齐阶段,我们收到了 Checkpoint 20 的 barrier。然后会逐级通知到下游的 task checkpoint 19 被取消了,同时也会通知 JM 当前 Checkpoint 被 decline 掉了。


在下游 task 收到被 cancelBarrier 的时候,会打印类似如下的日志:


DEBUG$taskNameWithSubTaskAndID: Checkpoint 19 canceled, aborting alignment.
或者
DEBUG$taskNameWithSubTaskAndID: Checkpoint 19 canceled, skipping alignment.
或者
WARN$taskNameWithSubTaskAndID: Received cancellation barrier for checkpoint 20 before completing current checkpoint 19. Skipping current checkpoint.
复制代码


上面三种日志都表示当前 task 接收到上游发送过来的 barrierCancel 消息,从而取消了对应的 Checkpoint。

2.1.2 Checkpoint Expire

如果 Checkpoint 做的非常慢,超过了 timeout 还没有完成,则整个 Checkpoint 也会失败。当一个 Checkpoint 由于超时而失败是,会在 jobmanager.log 中看到如下的日志:


Checkpoint 1 of job 85d268e6fbc19411185f7e4868a44178  expired before completing.
复制代码


表示 Chekpoint 1 由于超时而失败,这个时候可以可以看这个日志后面是否有类似下面的日志:


Received late message for now expired checkpoint attempt 1 from 0b60f08bf8984085b59f8d9bc74ce2e1 of job 85d268e6fbc19411185f7e4868a44178.
复制代码


可以按照 2.1.1 中的方法找到对应的 taskmanager.log 查看具体信息。


下面的日志如果是 DEBUG 的话,我们会在开始处标记 DEBUG


我们按照下面的日志把 TM 端的 snapshot 分为三个阶段,开始做 snapshot 前,同步阶段,异步阶段:


DEBUGStarting checkpoint (6751) CHECKPOINT on task taskNameWithSubtasks (4/4)
复制代码


这个日志表示 TM 端 barrier 对齐后,准备开始做 Checkpoint。


DEBUG2019-08-06 13:43:02,613 DEBUG org.apache.flink.runtime.state.AbstractSnapshotStrategy       - DefaultOperatorStateBackend snapshot (FsCheckpointStorageLocation {fileSystem=org.apache.flink.core.fs.SafetyNetWrapperFileSystem@70442baf, checkpointDirectory=xxxxxxxx, sharedStateDirectory=xxxxxxxx, taskOwnedStateDirectory=xxxxxx, metadataFilePath=xxxxxx, reference=(default), fileStateSizeThreshold=1024}, synchronous part) in thread Thread[Async calls on Source: xxxxxx_source -> Filter (27/70),5,Flink Task Threads] took 0 ms.
复制代码


上面的日志表示当前这个 backend 的同步阶段完成,共使用了 0 ms。


DEBUGDefaultOperatorStateBackend snapshot (FsCheckpointStorageLocation {fileSystem=org.apache.flink.core.fs.SafetyNetWrapperFileSystem@7908affe, checkpointDirectory=xxxxxx, sharedStateDirectory=xxxxx, taskOwnedStateDirectory=xxxxx,  metadataFilePath=xxxxxx, reference=(default), fileStateSizeThreshold=1024}, asynchronous part) in thread Thread[pool-48-thread-14,5,Flink Task Threads] took 369 ms
复制代码


上面的日志表示异步阶段完成,异步阶段使用了 369 ms


在现有的日志情况下,我们通过上面三个日志,定位 snapshot 是开始晚,同步阶段做的慢,还是异步阶段做的慢。然后再按照情况继续进一步排查问题。

2.2 Checkpoint 慢

在 2.1 节中,我们介绍了 Checkpoint 失败的排查思路,本节会分情况介绍 Checkpoint 慢的情况。


Checkpoint 慢的情况如下:比如 Checkpoint interval 1 分钟,超时 10 分钟,Checkpoint 经常需要做 9 分钟(我们希望 1 分钟左右就能够做完),而且我们预期 state size 不是非常大。


对于 Checkpoint 慢的情况,我们可以按照下面的顺序逐一检查

2.2.0 Source Trigger Checkpoint 慢

这个一般发生较少,但是也有可能,因为 source 做 snapshot 并往下游发送 barrier 的时候,需要抢锁(这个现在社区正在进行用 mailBox 的方式替代当前抢锁的方式,详情参考[1])。如果一直抢不到锁的话,则可能导致 Checkpoint 一直得不到机会进行。如果在 Source 所在的 taskmanager.log 中找不到开始做 Checkpoint 的 log,则可以考虑是否属于这种情况,可以通过 jstack 进行进一步确认锁的持有情况。

2.2.1 使用增量 Checkpoint

现在 Flink 中 Checkpoint 有两种模式,全量 Checkpoint 和 增量 Checkpoint,其中全量 Checkpoint 会把当前的 state 全部备份一次到持久化存储,而增量 Checkpoint,则只备份上一次 Checkpoint 中不存在的 state,因此增量 Checkpoint 每次上传的内容会相对更好,在速度上会有更大的优势。


现在 Flink 中仅在 RocksDBStateBackend 中支持增量 Checkpoint,如果你已经使用 RocksDBStateBackend,可以通过开启增量 Checkpoint 来加速,具体的可以参考 [2]。

2.2.2 作业存在反压或者数据倾斜

我们知道 task 仅在接受到所有的 barrier 之后才会进行 snapshot,如果作业存在反压,或者有数据倾斜,则会导致全部的 channel 或者某些 channel 的 barrier 发送慢,从而整体影响 Checkpoint 的时间,这两个可以通过如下的页面进行检查:



上图中我们选择了一个 task,查看所有 subtask 的反压情况,发现都是 high,表示反压情况严重,这种情况下会导致下游接收 barrier 比较晚。



上图中我们选择其中一个 operator,点击所有的 subtask,然后按照 Records Received/Bytes Received/TPS 从大到小进行排序,能看到前面几个 subtask 会比其他的 subtask 要处理的数据多。


如果存在反压或者数据倾斜的情况,我们需要首先解决反压或者数据倾斜问题之后,再查看 Checkpoint 的时间是否符合预期。

2.2.2 Barrier 对齐慢

从前面我们知道 Checkpoint 在 task 端分为 barrier 对齐(收齐所有上游发送过来的 barrier),然后开始同步阶段,再做异步阶段。如果 barrier 一直对不齐的话,就不会开始做 snapshot。


barrier 对齐之后会有如下日志打印:


DEBUGStarting checkpoint (6751) CHECKPOINT on task taskNameWithSubtasks (4/4)
复制代码


如果 taskmanager.log 中没有这个日志,则表示 barrier 一直没有对齐,接下来我们需要了解哪些上游的 barrier 没有发送下来,如果你使用 At Least Once 的话,可以观察下面的日志:


DEBUGReceived barrier for checkpoint 96508 from channel 5
复制代码


表示该 task 收到了 channel 5 来的 barrier,然后看对应 Checkpoint,再查看还剩哪些上游的 barrier 没有接受到,对于 ExactlyOnce 暂时没有类似的日志,可以考虑自己添加,或者 jmap 查看。

2.2.3 主线程太忙,导致没机会做 snapshot

在 task 端,所有的处理都是单线程的,数据处理和 barrier 处理都由主线程处理,如果主线程在处理太慢(比如使用 RocksDBBackend,state 操作慢导致整体处理慢),导致 barrier 处理的慢,也会影响整体 Checkpoint 的进度,在这一步我们需要能够查看某个 PID 对应 hotmethod,这里推荐两个方法:


  1. 多次连续 jstack,查看一直处于 RUNNABLE 状态的线程有哪些;

  2. 使用工具 AsyncProfile dump 一份火焰图,查看占用 CPU 最多的栈;


如果有其他更方便的方法当然更好,也欢迎推荐。

2.2.4 同步阶段做的慢

同步阶段一般不会太慢,但是如果我们通过日志发现同步阶段比较慢的话,对于非 RocksDBBackend 我们可以考虑查看是否开启了异步 snapshot,如果开启了异步 snapshot 还是慢,需要看整个 JVM 在干嘛,也可以使用前一节中的工具。对于 RocksDBBackend 来说,我们可以用 iostate 查看磁盘的压力如何,另外可以查看 tm 端 RocksDB 的 log 的日志如何,查看其中 SNAPSHOT 的时间总共开销多少。


RocksDB 开始 snapshot 的日志如下:


2019/09/10-14:22:55.734684 7fef66ffd700 [utilities/checkpoint/checkpoint_impl.cc:83] Started the snapshot process -- creating snapshot in directory /tmp/flink-io-87c360ce-0b98-48f4-9629-2cf0528d5d53/XXXXXXXXXXX/chk-92729
复制代码


snapshot 结束的日志如下:


2019/09/10-14:22:56.001275 7fef66ffd700 [utilities/checkpoint/checkpoint_impl.cc:145] Snapshot DONE. All is good
复制代码

2.2.6 异步阶段做的慢

对于异步阶段来说,tm 端主要将 state 备份到持久化存储上,对于非 RocksDBBackend 来说,主要瓶颈来自于网络,这个阶段可以考虑观察网络的 metric,或者对应机器上能够观察到网络流量的情况(比如 iftop)。


对于 RocksDB 来说,则需要从本地读取文件,写入到远程的持久化存储上,所以不仅需要考虑网络的瓶颈,还需要考虑本地磁盘的性能。另外对于 RocksDBBackend 来说,如果觉得网络流量不是瓶颈,但是上传比较慢的话,还可以尝试考虑开启多线程上传功能[3]。

3 总结

在第二部分内容中,我们介绍了官方编译的包的情况下排查一些 Checkpoint 异常情况的主要场景,以及相应的排查方法,如果排查了上面所有的情况,还是没有发现瓶颈所在,则可以考虑添加更详细的日志,逐步将范围缩小,然后最终定位原因。


上文提到的一些 DEBUG 日志,如果 flink dist 包是自己编译的话,则建议将 Checkpoint 整个步骤内的一些 DEBUG 改为 INFO,能够通过日志了解整个 Checkpoint 的整体阶段,什么时候完成了什么阶段,也在 Checkpoint 异常的时候,快速知道每个阶段都消耗了多少时间。

参考内容

[1] Change threading-model in StreamTask to a mailbox-based approach


[2] 增量 checkpoint 原理介绍


[3] RocksDBStateBackend 多线程上传 State


2019-09-19 08:006687

评论 1 条评论

发布
用户头像
第三张图上面有一个错别字,麻烦修改下,"看到类系下图" --> "看到类似下图“
2019-09-21 14:14
回复
没有更多了
发现更多内容

运维成本降低 50%,丽迅物流是如何应对大规模容器镜像管理挑战的

阿里巴巴云原生

阿里云 容器 云原生 镜像

【译】日志:每个软件工程师都应该了解实时数据的统一抽象【二】

Rae

kafka 架构 分布式 日志 原理

弯曲矫正技术概述

合合技术团队

人工智能 深度学习 图片处理

软件测试 | 测试开发 | 被测系统架构与数据流分析

测吧(北京)科技有限公司

测试

2022-9-30

留白的艺术

Go runtime:带你了解Go语言的GMP模型与goroutine调度

董哥的黑板报

Go 线程 操作系统 协程 runtime

软件测试 | 测试开发 | 测试平台开发-前端开发之Vue.js 框架的使用(二)

测吧(北京)科技有限公司

测试

软件测试 | 测试开发 | 测试平台开发-前端开发之Vue.js 框架(一)

测吧(北京)科技有限公司

测试

实现Promise的原型方法--前端面试能力提升

helloworld1024fd

JavaScript

【“玩物立志”-scratch少儿编程】亲手实现小猫走迷宫小游戏:其实挺简单

清风莫追

游戏 scratch 10月月更

TDengine3.0流式计算引擎语法规则介绍

TDengine

数据库 tdengine 企业号九月金秋榜

软件测试 | 测试开发 | 测试面试 | 某 BAT 大厂测试开发面试真题与重点解析

测吧(北京)科技有限公司

测试

【导航】FreeRTOS学习专栏目录 【快速跳转】

矜辰所致

目录 FreeRTOS 9月月更

面试官:能用JavaScript手写一个bind函数吗

helloworld1024fd

JavaScript

C语言太细了

清风莫追

c 10月月更

深度分析React源码中的合成事件

goClient1992

React

软件测试 | 测试开发 | 软件测试入门必会-流程管理平台

测吧(北京)科技有限公司

测试

软件测试 | 测试开发 | 一文带你了解测试流程的体系

测吧(北京)科技有限公司

测试

HummerRisk 云原生安全平台

HummerCloud

云计算 云原生 云安全

软件测试 | 测试开发 | 被测项目需求你理解到位了么?

测吧(北京)科技有限公司

测试

从React源码角度看useCallback,useMemo,useContext

goClient1992

React

软件测试 | 测试开发 | 黑盒测试方法论—等价类

测吧(北京)科技有限公司

测试

数据中台中事实表设计概述

穿过生命散发芬芳

数据中台 9月月更

TiDB Lightning导入超大型txt文件实践

TiDB 社区干货传送门

迁移 管理与运维

k8s Tidb 实践-运维篇

TiDB 社区干货传送门

数据库前沿趋势

百草味上线“本味甄果”系列罐装坚果 打造高品质坚果新标准

E科讯

软件测试 | 测试开发 | 软件项目管理与跨部门沟通协作

测吧(北京)科技有限公司

测试

边缘计算落地提速 天翼云Serverless边缘容器加速深耕市场

极客天地

TiFlash 源码阅读(九)TiFlash 中常用算子的设计与实现

TiDB 社区干货传送门

k8s Tidb实践-部署篇

TiDB 社区干货传送门

数据库前沿趋势

软件测试 | 测试开发 | 做为测试,那些必须掌握的测试技术体系

测吧(北京)科技有限公司

测试

Flink Checkpoint问题排查实用指南_AICon_邱从贤_InfoQ精选文章