☰
Prometheus+PushGateway监控Flink on YARN作业实战
2026/10/14 22:20:04 网站建设 项目流程

1. 为什么要用Prometheus+PushGateway盯Flink on YARN作业

Flink on YARN作业的监控,一直比普通单机进程的监控麻烦一个档次。原因很简单:YARN会把JobManager和TaskManager动态调度到不同节点上,容器端口每次作业启动都可能不一样,Prometheus那种主动去拉指标的模型往往吃不到活口。我自己最早试过直接用Flink的PrometheusReporter,发现一个很尴尬的问题——作业的JM(JobManager)地址虽然能拿到,但一堆TM(TaskManager)容器分布在集群各处,端口完全随机,Prometheus静态配置根本没法提前写好。

有个笨办法是每次作业启动后手动解析YARN日志去拿所有容器地址,再动态改Prometheus的target列表,但这样既脆弱又费人工。所以最后老老实实回到Prometheus+PushGateway+Grafana这套组合:Flink作业内部用PushgatewayReporter把指标主动推到PushGateway,Prometheus只需盯住一个稳定的PushGateway地址就行,Grafana负责把指标画成面板。这套方案不是什么黑科技,但胜在结构简单、贴合YARN动态调度场景,尤其适合做demo和中小规模集群的快速落地。

这个demo要解决的核心痛点是“作业跳、指标不能断”。YARN上的Flink作业生命周期是随时的,跑完就释放容器,如果还是按“固定target抓取”的思路,作业一停Prometheus就报Down,数据时序也会断裂。PushGateway相当于一个中转站,作业存活期间持续把指标推上来,作业停了指标还留在PushGateway里,虽然要多做清理,但至少在作业运行和刚结束时都能看到完整数据。

适合什么人参考?如果是刚接触监控体系、想把Flink作业的CPU、内存、延迟、吞吐量快速展示到Grafana上,这套方案是性价比最高的入门路线。如果有扫一批Flink作业做统一指标采集的需求,PushGateway的“可聚合”特性也很有价值。想再深入,可以在这个基础上接Alertmanager告警、做多集群联邦,思路一致,后面都能平滑扩展。

2. 监控架构与部署前的关键决策

2.1 完整的数据链路和组件分工

这套demo的链路是这样走的:

Flink作业内部Reporter → PushGateway → Prometheus → Grafana

Flink不是自己去抓指标,而是通过内置的PrometheusPushGatewayReporter,定期把JM、TM的指标序列化成Prometheus格式,然后HTTP推送到PushGateway的/metrics接口。PushGateway保存这些指标并等待Prometheus来拉取,Prometheus按固定间隔从PushGateway收集数据,写进自己的TSDB存储。Grafana再通过PromQL查询这些指标做可视化。

组件角色我常用一个比喻:Flink作业是“发快递的商家”,PushGateway是“菜鸟驿站”,Prometheus是“快递总仓”,Grafana是“前台可视化柜面”。商家不用知道总仓在哪,只需要把货送到驿站;总仓只需要固定去驿站揽收,不用关心哪个商家搬家了。这套模式最妙的地方在于“解耦”——作业地址再怎么变,Prometheus永远只认PushGateway这一个地址。

具体的组件分工见下表:

组件职责关键配置点
Flink PushgatewayReporter采集JM/TM指标并主动推送flink-conf.yaml中配置reporter
PushGateway缓存指标、暴露HTTP接口端口、写入频率、清理策略
Prometheus抓取、存储指标、执行PromQLscrape_configs、honor_labels
Grafana数据可视化、告警展示数据源URL、Dashboard JSON

对于demo规模,这四个组件可以全部部署在同一个内网节点上,只要端口不冲突、网络通就能跑通。生产环境可以把PushGateway和Prometheus分开部署,避免导入大量指标时相互影响。

2.2 版本兼容性判断

这个demo我推荐直接使用Flink自带的PushgatewayReporter,不需要额外引入第三方jar包。从Flink 1.11开始,PushgatewayReporter就已经内置在flink-metrics-prometheus模块里,1.12之后更加稳定。如果你用的是很老的Flink 1.9、1.10,就得去官方下载对应的flink-metrics-prometheus jar包放到lib目录下。现在的Flink版本基本都支持。

Prometheus选择2.x系列,任意一个近期版本都可以。Grafana建议选8.x或9.x以上版本,新版数据源配置、变量和面板编辑器的交互更顺手,api/v1/query响应也更快。如果是在老项目里沿用Grafana 7.x,倒也不是不能用,只是有些面板样例可能导入报版本兼容错误,需要手工修JSON。

2.3 部署形态选择

部署方式我分两种情况讲:

第一种是真实小集群。PushGateway可以放在JobManager可能访问到的一个固定内网IP上,或者放在一台和YARN ResourceManager同网段的管理机上。Prometheus也放同一台机器,减少网络跨段。Grafana和Prometheus同机或者另开一台,数据源指向Prometheus即可。

第二种是纯本机demo。比如你在自己电脑上想做验证,那就最简单——三个组件全部localhost,Flink作业如果是跑在本地模拟的YARN模式,reporter地址填localhost:9091就行。不过要注意,如果Flink最终是跑在Docker容器里,那reporter地址不能写localhost,你得写宿主机或者PushGateway容器对应的服务名,否则会把指标推到自己容器的端口上,外部根本收不到。

我建议部署时先把所有组件都跑起来,再通过命令行验证PushGateway的/metrics接口有没有数据,再启动Flink作业,这样排错链路最清晰。不要一上来就把Flink作业和Prometheus一起启动,容易分不清到底是谁没起来。

3. flink-conf.yaml 与 PushGateway 配置细节

3.1 打开PushGateWayReporter的正确姿势

核心配置都在Flink作业的flink-conf.yaml里。无论你是用Flink Standalone YARN模式,还是通过提交命令指定配置,最终都靠这些配置项控制指标推送行为。

最基本的配置如下:

metrics.reporter.promgateway.class: org.apache.flink.metrics.prometheus.PrometheusPushGatewayReporter metrics.reporter.promgateway.host: pushgateway主机IP metrics.reporter.promgateway.port: 9091 metrics.reporter.promgateway.jobName: flink_metrics metrics.reporter.promgateway.randomJobNameSuffix: true metrics.reporter.promgateway.removeRandomSuffixOnShutdown: true metrics.reporter.promgateway.groupingKey: k8s_cluster=demo metrics.reporter.promgateway.interval: 30 metrics.reporter.promgateway.batchWait: 8 metrics.reporter.promgateway.batchSize: 200

这里有几个容易弄混的参数,我说说我自己的理解:

jobName是PushGateway里一组指标的名称,默认是flink_metrics。如果同时跑多个Flink作业,不加区分就会互相覆盖。所以randomJobNameSuffix: true特别重要,它会自动在jobName后面拼一段随机字符,防止多个作业写同一组标签。removeRandomSuffixOnShutdown: true则是在作业正常关闭时,尝试把随机后缀移除并清理占用的指标组。这两个参数在迁移到YARN模式时非常实用,因为同一个集群上会有多个Flink作业并行。

groupingKey是给指标额外打业务标签的入口,格式是key=value用逗号分隔。比如groupingKey: appname=xx,env=prod,这样从指标字典来看,可以区分不同业务、不同环境的数据。

interval控制推送周期,单位是秒。默认值是30秒,如果你希望Grafana面板更灵敏,可以改成10秒甚至5秒。但PushGateway和Prometheus那边也要相应调短scrape间隔,比如Prometheus的scrape_interval: 15s。否则Flink推得更快,Prometheus拉得更慢,时序图还是会有毛刺和空洞。生产环境建议至少30秒以上,避免频繁推送造成PushGateway压力。

batchWait和batchSize是批量推送参数。batchWait单位也是秒,表示批量推送的等待时间;batchSize表示单次批量最多包含多少条指标。这些参数一般不需要频繁调整,但如果你的TM数量特别多,比如上百个TaskManager,那你可能要适当调大batchSize,否则一次推不完会延迟到下一轮,影响监控实时性。

有一点要提醒:metrics.reporter.promgateway.class的类名一定要写完整。有些老教程给的是org.apache.flink.metrics.prometheus.PrometheusPushGatewayReporter,如果你的Flink版本是1.11以后,这个没错。如果是低版本,要注意有没有对应的jar包。类名错了Flink不会启动失败,但会在TaskManager日志里刷Could not instantiate的报错。

3.2 标签设计与指标独立性

PushGateway的标签体系非常关键,也是最容易踩坑的地方。

Prometheus的指标模型是metric_name{label1="value1", label2="value2"} value。PushGateway的存储结构是“按 jobName + groupingKey 分组的”。如果两个作业使用了同样的jobName且randomJobNameSuffix: false,它们的指标会被合并到同一个分组里,导致两个作业的同一个指标名互相覆盖。

打个比方:作业A的flink_jobmanager_Status_JVM_Memory_Heap_Used和作业B的同名指标,如果标签完全一样,Prometheus会认为是同一个时序,后推送的会盖掉先推送的。数据就会跳来跳去。

所以多作业场景的标签设计基本原则是:至少用一个唯一标识(如作业名)作为groupingKey。比如:

metrics.reporter.promgateway.groupingKey: flink_job_name=my_real_time_etl

然后在Prometheus查询时,把flink_job_name作为一级过滤维度。这样即使两个作业都叫flink_metrics,只要flink_job_name不同,Prometheus也能区分出两套独立的时间序列。

如果你希望区分同一作业里的JobManager和TaskManager,Flink自动会带instance标签,里面会写主机名或容器ID。在Grafana面板里通常做法是把instance做成变量,方便只观察某个TaskManager。

3.3 PushGateway的清理与安全策略

PushGateway最大的毛病就是“指标会留在里面不消失”。Flink作业跑完正常退出,理论上reporter会调用delete方法清理该jobName下的指标;但如果作业被kill -9强杀、TaskManager容器被节点驱逐,PushGateway里就会残留一堆旧指标。这些旧指标会导致Grafana图上出现“幽灵数据”——明明作业已经停了,面板上指标还在跳动。

清理方式有两种:

第一种是在PushGateway上加上--persistence.file,用文件持久化保存指标,重启不丢。如果文件太大会导致启动和写入变慢。demo场景一般不启用持久化,直接用内存模式。

第二种是手动清理,调用PushGateway的HTTP API删除指定job下的所有指标:

curl -X DELETE http://pushgateway-host:9091/metrics/job/flink_metrics

如果使用了random后缀,你需要先找到实际jobName。通过访问http://pushgateway-host:9091/页面,能看到当前所有jobName和label组合,然后再去删。也可以用curl直接看接口返回的指标头:

curl -s http://pushgateway-host:9091/metrics | head -20

安全方面,PushGateway本身没有任何鉴权能力,谁都能往上面推数据,谁都能删数据。所以在生产环境不要直接暴露公网IP,建议用防火墙限制只允许Flink作业所在网段和Prometheus所在网段访问9091端口。如果公司内部有统一的认证网关,也可以考虑在前面加一层反向代理做基础白名单。

4. Prometheus 抓取配置与 Grafana 展示

4.1 Prometheus抓取PushGateway的配置要点

Prometheus抓取PushGateway的配置看起来不长,但有两个坑非常关键。一个是honor_labels,一个是job_name的聚合。

先看一个能直接用的prometheus.yml片段:

scrape_configs: - job_name: 'pushgateway' scrape_interval: 15s static_configs: - targets: ['pushgateway-host:9091'] honor_labels: true

honor_labels: true的意思是,如果PushGateway上报的指标带上的是来自Flink的分组标签,Prometheus要“尊重”这些标签,不要用自身的instance或job标签去覆盖它们。

不加这个参数会怎样?默认honor_labels: false时,Prometheus会把PushGateway侧的标签合并到对外指标里,但一旦发现冲突,优先保留Prometheus侧抓取配置里的job和instance标签。这就会导致你在Grafana里通过job或instance变量筛选时,看到的可能不是Flink分组标签里指定的作业名,而是Prometheus配置里的job_name: 'pushgateway'。这样一来,多作业区分的核心维度就失效了。

如果你需要更细粒度的区分,比如不同Flink作业的指标都推到同一个PushGateway地址,那么Flink侧的groupingKey、random后缀生成的job标签会各不相同。把honor_labels: true打开以后,Prometheus会保留这些作业级标签,查询时就能按作业筛选。

关于抓取周期:如果你的Flink推送间隔是30秒,那么Prometheus的scrape_interval设成15秒就够了,不要设成1秒。PushGateway并不是被Prometheus拉完就把数据清空,它会持续保留内存里的指标副本,你拉得快只会增加网络传输压力,不会让指标更新得更快。

4.2 用业务标签和变量隔离多个Flink作业

当集群里同时跑五六个Flink作业时,Grafana面板不可能只针对某一个作业静态写死。我的推荐做法是,在Flink的groupingKey里至少指定一个稳定的作业名标签,然后在Grafana里做成一个job变量。

比如每个作业的flink-conf.yaml里这样配:

metrics.reporter.promgateway.groupingKey: flink_app=job_a_202401

那么Prometheus拉到的指标中会带flink_app="job_a_202401"标签。Grafana新建Dashboard后,在变量设置里添加一个变量,查询类型选Label values,Label选择flink_app,数据源指向Prometheus。面板标题和查询条件里都引用这个变量,比如:

sum(flink_jobmanager_Status_JVM_Memory_Heap_Used{flink_app="$flink_app"}) by (flink_app)

这个方法能保证你在切换顶部变量时,所有面板同时切换到对应作业的数据。而且不用修改Prometheus配置,纯靠标签就能完成隔离。

4.3 Grafana数据源配置与核心面板示例

Grafana部分其实不难,第一步先加数据源: Configuration → Data Sources → Add data source → Prometheus,填上Prometheus的HTTP地址,比如http://prometheus-host:9090,然后点击Save & Test,提示成功即可。

接下来创建Dashboard。你可以手动一个一个面板添加,也可以找个现成的Flink Dashboard JSON导入。我建议自己先手写几个核心面板,对PromQL理解会更深;都熟悉了再导入完整的JSON做增强。

下面是几个最常用的、能度量的核心指标查询:

监控维度PromQL示例
JobManager堆内存使用flink_jobmanager_Status_JVM_Memory_Heap_Used
TaskManager堆内存使用sum(flink_taskmanager_Status_JVM_Memory_Heap_Used) by (instance)
当前运行作业数flink_jobmanager_Status_NumberOfRunningJobs
作业重启次数flink_jobmanager_Job_Status_Restarting
上游输入记录速率flink_taskmanager_job_task_operator_currentNumRecordsInRate
连接下游的当前发送速率flink_taskmanager_job_task_operator_currentNumRecordsOutRate

这些指标名在我的Flink 1.12版本上是对的,如果版本不同可以通过PushGateway页面或Prometheus的{job="flink_metrics"}前缀查看全部指标名,真找不到时用grep flink_taskmanager | head -50快速翻。

Grafana面板的类型建议选Time series。Graph面板在新版本Grafana里已经慢慢被Time series取代,Time series能更好地处理动态标签,支持自动单位换算。比如内存用量可以设置单位bytes。如果看到图上单位显示成KB数量级那种怪怪的值,大概率是没设单位,或者查询结果本身就带了不同单位。

补充一个实用技巧:在面板里经常需要按instance聚合多个TaskManager。如果TM数量太多,面板会特别乱。此时用topk只显示Top N:

topk(10, sum(flink_taskmanager_Status_JVM_Memory_Heap_Used) by (instance))

这样能一眼看到哪些TaskManager吃内存最凶,特别适合排查内存倾斜。

5. 实操过程中的“坑”与排查

5.1 PushGateway残留指标导致Grafana“假活”

这个坑我在一次生产作业重启时踩得很深。当时Flink作业做了yarn application -kill,然后立刻重新提交了一个同名任务。结果Grafana面板上显示的指标前一分钟还是旧任务的,后一分钟就变成新任务的,中间好像没断过,但两个任务的数据口径根本不一样,很容易误判。

后来发现是旧作业的PushGateway清理没生效。Flink正常退出时确实调用了delete,但那次强杀导致delete没执行。解决方案分三层:

  1. 在Flink作业取消或失败时,专门写一个钩子脚本,调用curl -X DELETE /metrics/job/...,确保清理。
  2. 在PushGateway外面包一个周期任务,每10分钟调用API遍历并删掉超过30分钟没更新的job分组。
  3. 在Prometheus配置里给pushgateway这个job设置honor_labels: true,同时查询时用up{job="pushgateway"}快速检查PushGateway本身是否存活。

这三层下来,基本不怕残留指标了。

5.2 多作业标签冲突和随机后缀的两难

使用randomJobNameSuffix: true后,确实避免了不同作业的覆盖,但引入了另一个问题:作业每次重启都会生成一个新的随机后缀,Prometheus里的job标签也跟着变化。Grafana面板的变量列表会越来越长,而且同一个作业的历史数据分布在多个随机job标签中,很难按作业聚合。

我后来采用的方案是:放弃随机后缀,改用固定jobName,但把作业ID写进groupingKey。

比如每个作业在提交时,通过-Dmetrics.reporter.promgateway.groupingKey=flink_app=job_a_001传入,保证每个作业的flink_app完全独立。这样job标签始终是同一个flink_metrics,而flink_app标签区分不同作业。重启后固定标签不变,历史数据能串联起来。

如果你的一个作业会动态启动多个TaskManager,只要TM内部配置一样,它们的标签也一致,PushGateway会把同一分组下的指标聚合得很好。这一点我实测过,确实没问题。

5.3 抓取为空或时序断点

从头到尾排查链路,我会按顺序检查:

  1. PushGateway是否存活:curl http://pushgateway-host:9091/metrics | grep flink_jobmanager,有输出说明Flink推上来了。
  2. Prometheus是否抓到目标:在Prometheus UI的Status → Targets里看pushgateway这个job是否为UP。如果是DOWN,检查网络、端口、Prometheus配置里的地址。
  3. Grafana数据源是否连通:Debug查询里执行rate(flink_taskmanager_Status_JVM_Memory_Heap_Used[5m])看是否有返回。
  4. 指标名是否随时间改变:有的Flink指标名带__operator__等变量,面板写死会查不到。

如果Prometheus能抓到但Grafana面板空白,最常见的原因是查询里用了rate()这类函数,但指标本身是Counter型,在第一次出现前没有足够的样本,所以返回空。这种时候可以先直接用原始指标看一下曲线,比如flink_jobmanager_Status_NumberOfRunningJobs,如果这个有值,说明链路没问题,面板过滤条件有问题。

5.4 常见问题速查表

问题现象可能原因处理办法
PushGateway页面上没有Flink指标Flink reporter配置没生效检查类名,查看TaskManager日志是否有异常
多个Flink作业指标互相覆盖jobName相同且无随机后缀设置randomJobNameSuffix或使用groupingKey区分
作业停止后Grafana仍显示旧数据PushGateway残留指标手动调用delete API,增加定时清理
Prometheus Target处于DOWN网络不通、端口错误、防火墙拦截检查连通性、端口占用、防火墙放行
Grafana面板变量没有作业选项honor_labels未开启或标签值不存在设置honor_labels: true,确认groupingKey已生效
查询时显示多个重复的随机job名randomJobNameSuffix产生的历史残留清理PushGateway,或改为固定jobName+groupingKey

这套速查表我每次搭新环境都会复制一份,按行排查效率很高。

6. 关于这套demo,我最后想说的

这套监控方案我前前后后调了小一个月,踩过最深的坑不是组件配置,而是没有先做标签设计就匆匆上线,后面不断补标签、加随机后缀,导致Grafana面板改了一版又一版。如果你现在正要搭,我强烈建议先列一份标签清单:每个Flink作业的作业名、环境、业务线、版本号,这些要写进groupingKey,再落到Prometheus查询里。标签一旦定好,后续所有面板和告警都能稳定复用。

另外,PushGateway不适合长期保留大量指标,它只是临时中转站。如果你要做长周期历史趋势分析,监控数据最终应该落到Prometheus的TSDB或者远程存储里。Prometheus本身会按保留策略自动清理旧数据,所以你不用担心磁盘一直涨,但这个demo里如果直接把Grafana默认纵轴调成“Last 7 days”,数据很可能是空的,因为Prometheus默认保留15天,你可以按需调整。

一个小技巧收尾:在Flink作业里把自定义指标也推到PushGateway非常方便,比如flink_jobmanager_custom_event_total,只需要在代码里用MetricGroup注册一个Counter,剩下的事全由reporter代劳。这样这套监控方案就不只是看基础资源,连业务数据进度也能一起监控。对我来说,能把业务指标和资源指标放同一块面板,才算是真的把Flink作业看明白了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询