4. 指标采集:JMX、Prometheus Pushgateway、自定义Metric Reporter、Flink内置指标

监控系统能不能干活,关键看指标能不能采上来。说白了,你连数据都拿不到,后面那些告警、大盘、根因分析全是空谈。

这一章我们聊聊Flink指标采集的四种主流方式。每种方式都有它的适用场景,也有各自的坑。我这些年踩过的雷,今天一并说清楚。

4.1 Flink内置指标——开箱即用的基础数据

Flink本身自带了一套指标系统,你不需要额外写代码就能拿到。这些指标覆盖了Job、Task、算子、网络、内存、IO等方方面面。

我个人习惯把内置指标分成三类:

分类 典型指标 说明
Job级别 numRestarts、lastCheckpointSize、numberOfFailedCheckpoints 反映作业整体健康度
Task级别 numRecordsInPerSecond、numRecordsOutPerSecond、currentInputWatermark 反映算子处理能力与延迟
网络与内存 inPoolUsage、outPoolUsage、memorySegmentsAvailable 反映资源瓶颈
小提示:内置指标默认通过JMX暴露。你可以在flink-conf.yaml里配置metrics.reporter,把数据推到外部系统。

举个例子,配置Prometheus Reporter:

metrics.reporter.prom.class: org.apache.flink.metrics.prometheus.PrometheusReporter
metrics.reporter.prom.port: 9250

启动后访问 http://<taskmanager>:9250 就能看到Prometheus格式的指标。

4.2 JMX——Java生态的老牌选手

JMX(Java Management Extensions)是Java自带的监控管理框架。Flink的指标系统默认就注册到了MBean Server上,你可以用JConsole、VisualVM或者JMX客户端直接连上去看。

嗯,这里要注意。JMX虽然方便,但在生产环境里我一般不推荐直接用它做指标采集。为什么?

  • 性能开销:频繁的JMX轮询会触发Full GC,尤其是当MBean数量多的时候。
  • 安全性:JMX默认不加密,暴露在外网就是找死。
  • 扩展性:JMX是点对点的,不适合大规模集群。

我曾经在一个大集群上直接用JMX拉指标,结果把TaskManager的GC时间拉高了30%。从那以后,JMX我只用来做临时调试,生产环境还是走Prometheus。

避坑指南:如果你非要用JMX,记得加上认证和SSL。另外,轮询间隔不要小于15秒,否则容易把JVM搞崩。

4.3 Prometheus Pushgateway——适合短生命周期任务

Prometheus默认是拉模式(Pull),但Flink作业是动态的,TaskManager随时可能扩缩容。拉模式需要服务发现,配置起来比较麻烦。

Pushgateway的出现解决了这个问题。Flink把指标推给Pushgateway,Prometheus再从Pushgateway拉。这样一来,你就不需要维护服务发现了。

配置方式也很简单:

metrics.reporter.promgateway.class: org.apache.flink.metrics.prometheus.PrometheusPushGatewayReporter
metrics.reporter.promgateway.host: pushgateway.example.com
metrics.reporter.promgateway.port: 9091
metrics.reporter.promgateway.jobName: my_flink_job
metrics.reporter.promgateway.randomJobNameSuffix: true

这里有个坑——Pushgateway不会自动清理过期指标。如果你的作业重启了,旧的指标还留在Pushgateway里,会导致数据混乱。

我的做法是:在作业启动时,先调用Pushgateway的API删除旧指标,再开始推送。

curl -X DELETE http://pushgateway:9091/metrics/job/my_flink_job
核心要点:Pushgateway适合短生命周期或批处理任务。对于长跑流作业,我更推荐用Pull模式+服务发现。

4.4 自定义Metric Reporter——按需定制

内置的Reporter不一定满足所有场景。比如你想把指标写入Elasticsearch、InfluxDB或者自研的监控系统,那就得自己写Reporter。

实现一个自定义Reporter其实不复杂,核心就三步:

  1. 实现 org.apache.flink.metrics.reporter.MetricReporter 接口
  2. 在 open() 方法里初始化连接
  3. 在 report() 方法里把指标发出去

我贴一个简化版的HTTP Reporter示例:

public class HttpReporter implements MetricReporter {

    private HttpClient client;
    private String endpoint;

    @Override
    public void open(MetricConfig config) {
        this.endpoint = config.getString("endpoint", "http://localhost:8080/metrics");
        this.client = HttpClient.newHttpClient();
    }

    @Override
    public void report() {
        // 遍历所有注册的指标,组装成JSON发送
        String json = buildJsonFromMetrics();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(endpoint))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(json))
                .build();
        client.sendAsync(request, HttpResponse.BodyHandlers.discarding());
    }

    @Override
    public void close() {
        client.close();
    }
}
注意:report()方法是在Flink的Metrics定时器线程里调用的。不要在report()里做耗时操作,否则会阻塞其他Reporter。我一般用异步发送,或者把数据先写到本地队列,再批量发送。

4.5 四种方式对比与选型建议

说了这么多,到底该用哪种?我整理了一张对比表:

方式 优点 缺点 推荐场景
Flink内置指标 零配置、覆盖全面 需要配合Reporter才能外发 所有场景的基础监控
JMX 原生支持、调试方便 性能差、不安全、不适合大规模 开发调试、临时排查
Prometheus Pushgateway 无需服务发现、配置简单 指标残留、单点故障 短生命周期任务、批处理
自定义Metric Reporter 完全可控、灵活 开发成本高、需要维护 对接自研监控系统

我个人推荐的生产方案是:内置指标 + Prometheus Pull模式。配合Kubernetes的服务发现,基本能覆盖99%的场景。Pushgateway只用来兜底,比如作业启动阶段或者临时任务。

4.6 本章知识体系

下面这张图梳理了四种指标采集方式的关系与数据流向:

Flink指标采集方式架构图 Flink指标采集方式架构图 Flink集群 JobManager TaskManager 内置指标系统 JMX JConsole / VisualVM 临时调试 Pushgateway 推送指标 短生命周期任务 Prometheus Pull 服务发现 + 拉取 生产环境推荐 自定义Reporter Elasticsearch / InfluxDB 自研监控系统 选型建议 生产环境:Pull模式 短任务:Pushgateway 调试:JMX 定制:自定义Reporter

从图里可以看得很清楚:Flink内置指标是数据源头,四种采集方式各有各的出口。选型时不要贪多,根据你的基础设施和作业类型来定。