滴滴 Flink 指标系统的架构设计与实践

毫不夸张地说,Flink 指标是洞察 Flink 任务健康状况的关键工具,它们如同 Flink 任务的眼睛一般至关重要。简而言之,这些指标可以被理解为滴滴数据开发平台实时运维系统的数据图谱。在实时计算领域,Flink 指标扮演着举足轻重的角色,例如,实时任务的消费延迟和检查点失败的警报都是基于对 Flink 报告的指标进行监控而触发的;同时,许多实时任务智能诊断的关键决策点也是依 Flink 指标来制定的。

鉴于 Flink 指标系统的重要性,深入理解其工作原理显得尤为必要,这是灵活运用 Flink 指标系统的前提。作为一名平台工程师,我尝试对 Flink 的原理进行一次剖析,如果存在任何不准确之处,敬请各位指正。

Flink 指标系统的核心概念

接下来我们将探讨一些核心概念,它们是理解 Flink 指标系统不可或缺的基础。

Metric Reporters

Metric Reporter 是 Flink 用于导出指标数据的接口,通过 flink-conf.yaml 文件可以轻松配置所需的 MetricReporter。Flink 提供了多种 MetricReporter 的实现,包括 Prometheus、Datadog 等,以满足不同的监控需求。

值得注意的是,尽管 Flink 提供了众多 MetricReporter 的实现,但它如何根据需要动态加载这些实现呢?我们将在后文关于弹性设计的讨论中深入分析这一机制,现在先留个悬念。

MetricReporter 支持两种指标上报方式:Push 和 Pull。具体不赘述了,我们直接引用官方文档中的描述:

Metrics are exported either via pushes or pulls.

Push-based reporters usually implement the Scheduled interface and periodically send a summary of current metrics to an external system.

Pull-based reporters are queried from an external system instead.

滴滴内部的Metric Reporters

滴滴内部没有采用社区的MetricReporter,而是根据滴滴内部实际情况,自研了flink-metrics-kafka。简单来讲,采用push的方式,

滴滴并未使用社区提供的 MetricReporter,而是根据自身需求自主研发了 flink-metrics-kafka。简单来说,该系统采用推送 Push 方式,周期性将 Flink 计算的指标推送到 kafka topic 当中。下文中的实现原理,也是基于 flink-metrics-kafka 介绍的。

Metrics type

Flink 社区对指标进行了高度抽象,定义了四种主要的指标类型:Counter、Gauge、Histogram 和 Meter。

  • Counter:这是一种简单的计数器,用于记录事件的数量。

  • Gauge:这种指标非常灵活,可以返回任意类型的统计数据。Gauge 可以看作是 Counter 的泛化版本。

  • Histogram:正如其名,Histogram 表示的是一系列长整型数值的分布情况,常用于绘制直方图。

  • Meter:这种指标用于度量平均吞吐量,适用于评估系统的处理能力。

滴滴内部的 Metered

在滴滴内部,我们独创了一种名为 Metered 的指标类型(请注意与 Meter 区分),专门用于衡量一段时间内的指标数值。这包括了时间段内的平均值、最大值、最小值以及计数等。实际上,我们内部使用的许多指标都是基于 Metered 进行计算的。

View

另一个关键概念是 View,它通常与 Metric 结合使用。让我们先来了解一下 View 的定义:

An interface for metrics which should be updated in regular intervals by a background thread.

换句话说,View 为 Metric 提供了一种定时刷新的能力。

Scope

Scope 可以简单地理解为命名空间,它允许在指标名称前添加一系列前缀。我个人认为 Scope 的主要作用是为了区分不同来源或类型的指标,以便于管理和识别。

系统指标

Flink 社区提供了丰富的开箱即用的指标,主要集中在系统性能方面,比如CPU、内存等。这部分内容不是本文重点,下文我们会重点讲解一个滴滴内部非常重要的指标:消费延迟。

Flink 指标系统的弹性设计

作为一款成功的分布式实时计算引擎,Flink 在指标系统设计上展现出了其独特之处。它不仅对指标上报进行了标准化定义和设计,还充分考虑了指标上报实现的多样性和可扩展性问题,因此我将之称为指标系统的弹性设计。下面,我们将详细分析 Flink 是如何实现这一设计的。

首先,我们来看看 Flink 对 MetricReporter 接口的定义。这个接口的定义非常简洁,其中包含三个关键信息:

1、open 和 close 方法分别在 MetricReporter 初始化和关闭时被调用。以滴滴内部的 KafkaReporter 实现为例,其主要功能是 Kafka 客户端的初始化和关闭操作。

2、notifyOfAddedMetric 和 notifyOfRemovedMetric 方法的主要作用是在 MetricGroup 添加或删除指标时,通知 MetricReporter,使其能够感知需要发送哪些指标。Flink 对 MetricReporter 进行了基础实现 AbstractReporter,我们可以看到在调用 notifyOfAddedMetric/notifyOfRemovedMetric 方法时,主要是在内存中维护了对指标的引用。

3、Flink 框架是如何加载并初始化 MetricReporter 的呢?源码中的注释给了我们提示:

>Reporters are instantiated via a {@link MetricReporterFactory}.

这意味着,MetricReporter 是通过 MetricReporterFactory 创建的(当然,在实际实现中,如果用户没有定义 MetricReporterFactory 的实现,也可以通过反射的方式初始化 MetricReporter)。

MetricReporterFactory 的定义是典型的工厂模式,注释中也包含了丰富的信息。简单来说,MetricReporterFactory 的实现类是通过 Java SPI 机制加载和实例化的。这里实际上是 Flink 指标系统实现弹性设计的关键所在。

也就是说,Flink 框架能够通过 Java SPI 机制按需加载 MetricReporterFactory 的实现类,再通过 MetricReporterFactory 实例化各种 MetricReporter。

MetricReporter 是 Flink 对指标系统的规范,MetricReporterFactory 的 SPI 加载机制为框架提供了灵活性。用户可以直接使用社区已经实现的指标系统,也可以自定义指标系统(比如,滴滴的 KafkaReporter)。本质上来说,这是一种遵循开闭原则的设计思想。

类似地,如果业务系统中有明确的业务逻辑,平台可以进行沉淀,同时将不同类型的需求通过 SPI 接口暴露出来,由业务方自行实现和维护,平台则按需加载业务方实现的 Jar 包即可,这就是插件思想的体现。

下面,我们将在源码层面详细分析弹性设计背后的实现细节:

当 Flink 启动 TaskManager 时,会触发 ReporterSetup 的初始化,其中的秘密都隐藏在这个类里。

让我们来详细分析一下 ReporterSetup 的 fromConfiguration 方法。简而言之,这个方法的核心步骤有两个:

  • 第一步是通过 SPI 方式加载 MetricReporterFactory。

  • 第二步是实例化 MetricReporter。

接下来,我们来分析通过 SPI 方式加载 MetricReporterFactory 的过程。ServiceLoader.load 是关键所在,我们可以看到它并没有传入 ClassLoader,也就是说它默认使用了 AppClassLoader(Flink 还支持 PluginManager 加载 MetricReporterFactory,本文不展开讨论,但其本质也是通过自定义类加载器加载不同指标系统实现的 jar 包)。

然后,我们再来分析一下 MetricReporter 的实例化过程。

最后,让我们来看一个真实的 MetricReporterFactory 实现类,以便对整个过程有更具体的了解。

Flink 指标注册和周期上报

接下来,我们将详细分析 Flink 指标注册与周期上报指标的实现原理。

指标注册

注册 Flink 指标的过程非常简单,可以直接参考官网的介绍。

Flink 通过 MetricGroup 接口注册指标,这一功能的实现最终委托给了抽象类 AbstractMetricGroup 的 addMetric 方法。AbstractMetricGroup 将指标最终注册到了 MetricRegistry。MetricRegistry 是 MetricReporter 和指标之间的桥梁,负责跟踪所有已注册的指标。整体流程如下图所示:

核心源码如下图所示:

总结一下,当 Flink 注册指标时,借助 MetricRegistry 的桥梁作用,最终将指标通知给了所有加载的 MetricReporter。因此,MetricReporter 在上报指标时,能够感知到 Flink job 中所有的指标。

周期上报

Flink 提供了周期性上报指标的能力,例如,滴滴内部的指标支持 10 秒和 1 分钟两种上报指标的频率,周期性上报指标为实时观测 Flink 任务运行的健康情况提供了可能。那么,Flink 是如何实现这一点的呢?

首先,我们需要了解接口 Scheduled,实现了 Scheduled 接口的 MetricReporter,Flink 会自动支持周期性上报的能力。

ReporterSetup 通过 SPI 的方式加载 MetricReporterFactory,在初始化 MetricReporter 后,同样会注册到 MetricRegistry。实现周期性上报的秘密,就在这里!

MetricRegistry 维护了一个 ScheduledExecutorService 线程池,根据 MetricReporter 配置的上报频率,周期性地触发 ReporterTask 的运行。ReporterTask 的定义一目了然,这里就不再赘述了。

一个例子 - 消费延迟指标是如何计算的?

在上一节关于 Flink 指标系统的弹性设计中,我们已经了解到 MetricReporter 主要负责将指标暴露给外部系统。同时,我们也介绍了 MetricReporter 如何感知 Flink 指标的注册,并能够周期性地上报这些指标。

除此之外,还有一个非常重要的环节值得我们关注:Flink 指标是如何计算的?

Flink 拥有众多的指标,其中包括许多内置的系统指标,它们的计算方式也各不相同。在这里,我将为大家介绍一个在日常工作中最为常见的指标:Flink 消费延迟指标。

消费延迟指标的计算公式如下(公式一):Max(数据进入 Flink Source 算子的机器时间 - 数据写入消息队列的时间)

那么,在源码层面,这个指标是如何计算并收集的呢?

消费延迟指标是由 ConnectorSourceIOMetricGroup 注册的。当 Flink Connector 消费一条数据后,会触发一次「公式一」的计算。

消息延迟指标最终由指标类型 MeteredView 计算,MeteredView 是上文提到的 Metered 和 View 接口的实现类。实现 View 接口主要是为了周期性地刷新指标的计算。

MeteredView 在内部维护了两个大小为 13 的循环数组,分别用于记录每次计算的消费延迟值和上报的次数。

每次计算消费延迟指标时,会更新最近 5 秒内延迟指标的累积和以及上报次数。

当 View 接口的 update 方法每 5 秒被触发执行时,会计算最近 1 分钟延迟指标的均值。

消费延迟指标最近 1 分钟的最大和最小值分别由两个数组维护,逻辑相对简单,这里就不再赘述了。

Flink 指标在滴滴内部的使用场景

Flink上报的指标在滴滴数据开发平台上的实时计算平台应用广泛,归纳来讲,主要有三类:

数据曲线

实时运维所看到的所有数据曲线指标均来源于本文所介绍的 Flink 指标系统。

监控告警

滴滴数据开发平台实时任务的消费延迟告警、Checkpoint 失败监控告警等功能依赖于 Flink 指标系统上报的指标。这些指标经过加工清洗和任务维度聚合后,实时监控任务是否触发了告警阈值。

实时任务智能诊断

该功能的决策树依赖于大量的 Flink 指标。结合 Flink 指标的结果,可以诊断任务出现问题的原因所在。

总结

作为一名平台工程师,深入研究 Flink 指标的应用以及 Flink 指标系统的架构与实践,让我受益匪浅。在这个过程中,我不仅汲取了优秀框架的设计理念,还从平台的视角更加全面地理解了 Flink 指标的实际应用,从而更深刻地理解了 Flink 指标背后的深层含义。

如果您觉得这篇文章对您有所帮助,请不吝点赞。您的认可和鼓励将是我持续前行的动力!

相关推荐
samLi06209 分钟前
【更新】中国省级产业集聚测算数据及协调集聚指数数据(2000-2022年)
大数据
Mephisto.java12 分钟前
【大数据学习 | Spark-Core】Spark提交及运行流程
大数据·学习·spark
EasyCVR1 小时前
私有化部署视频平台EasyCVR宇视设备视频平台如何构建视频联网平台及升级视频转码业务?
大数据·网络·音视频·h.265
hummhumm1 小时前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
科技象限2 小时前
电脑禁用U盘的四种简单方法(电脑怎么阻止u盘使用)
大数据·网络·电脑
天冬忘忧3 小时前
Kafka 生产者全面解析:从基础原理到高级实践
大数据·分布式·kafka
青云交3 小时前
大数据新视界 -- Hive 数据仓库:构建高效数据存储的基石(下)(2/ 30)
大数据·数据仓库·hive·数据安全·数据分区·数据桶·大数据存储
zmd-zk3 小时前
flink学习(2)——wordcount案例
大数据·开发语言·学习·flink
电子手信4 小时前
知识中台在多语言客户中的应用
大数据·人工智能·自然语言处理·数据挖掘·知识图谱
隔着天花板看星星4 小时前
Kafka-Consumer理论知识
大数据·分布式·中间件·kafka