Flink Metrics 实战自定义指标、系统指标、排障观测一把梭

1. 你到底在监控什么

Flink 的指标大体分两类:

  • 自定义指标:你在算子代码里主动埋点,回答"我的业务逻辑现在怎么样了?"
  • 系统指标:Flink 默认就有的 JVM、网络、checkpoint、背压、状态访问等指标,回答"作业为什么慢/卡/抖?"

这两类的组合,才是生产定位问题的最短路径:系统指标定位"哪一层出问题",自定义指标定位"业务哪一步出问题"。

2. 在算子里注册指标:RichFunction + MetricGroup

只要你的函数继承 RichFunction(如 RichMapFunction / RichFlatMapFunction / RichProcessFunction),就能在 open() 里拿到指标组:

java 复制代码
MetricGroup mg = getRuntimeContext().getMetricGroup();

然后在上面注册 Counter / Gauge / Histogram / Meter。

3. 四种指标类型怎么用

3.1 Counter:计数器(最常用)

用来统计"发生了多少次",比如处理条数、异常条数、重试次数。

java 复制代码
public class MyMapper extends RichMapFunction<String, String> {
  private transient Counter counter;

  @Override
  public void open(OpenContext ctx) {
    this.counter = getRuntimeContext()
      .getMetricGroup()
      .counter("myCounter");
  }

  @Override
  public String map(String value) {
    counter.inc();
    return value;
  }
}

如果你想用自己的实现也可以:

java 复制代码
counter = getRuntimeContext()
  .getMetricGroup()
  .counter("myCustomCounter", new CustomCounter());

3.2 Gauge:随取随算(状态型指标)

Gauge 适合暴露"当前值",比如队列长度、缓存命中率、当前批次大小、最近一次耗时等。

java 复制代码
public class MyMapper extends RichMapFunction<String, String> {
  private transient int valueToExpose = 0;

  @Override
  public void open(OpenContext ctx) {
    getRuntimeContext()
      .getMetricGroup()
      .gauge("MyGauge", (Gauge<Integer>) () -> valueToExpose);
  }

  @Override
  public String map(String value) {
    valueToExpose++;
    return value;
  }
}

注意:reporter 往往会把 Gauge 返回的对象转成 String,因此返回类型最好有清晰的 toString()

3.3 Histogram:分布统计(看 P50/P95/P99 的利器)

Histogram 用来度量一串 long 值的分布,比如处理耗时、批次大小、状态访问耗时等。Flink 本身不内置默认实现,但支持 Dropwizard/Codahale 的 wrapper。

依赖:

xml 复制代码
<dependency>
  <groupId>org.apache.flink</groupId>
  <artifactId>flink-metrics-dropwizard</artifactId>
  <version>2.2.0</version>
</dependency>

注册示例:

java 复制代码
public class MyMapper extends RichMapFunction<Long, Long> {
  private transient Histogram histogram;

  @Override
  public void open(OpenContext ctx) {
    com.codahale.metrics.Histogram dw =
      new com.codahale.metrics.Histogram(new SlidingWindowReservoir(500));

    this.histogram = getRuntimeContext()
      .getMetricGroup()
      .histogram("myHistogram", new DropwizardHistogramWrapper(dw));
  }

  @Override
  public Long map(Long value) {
    histogram.update(value);
    return value;
  }
}

建议:Histogram 更适合做"耗时分布",别用它做计数。

3.4 Meter:吞吐率(每秒多少事件)

Meter 适合统计"平均吞吐",比如每秒处理条数、每秒请求数。你只需要 markEvent()

java 复制代码
public class MyMapper extends RichMapFunction<Long, Long> {
  private transient Meter meter;

  @Override
  public void open(OpenContext ctx) {
    this.meter = getRuntimeContext()
      .getMetricGroup()
      .meter("myMeter", new MyMeter());
  }

  @Override
  public Long map(Long value) {
    meter.markEvent();
    return value;
  }
}

同样也可以用 Dropwizard 的 wrapper(依赖同上)。

4. 指标命名与 Scope:别让你的指标在监控系统里"撞名"

每个指标最终都会变成一个 identifier,结构是:

系统 scope +(可选 user scope)+ metric name

默认分隔符是 .,可用 metrics.scope.delimiter 改。

4.1 User Scope:用 addGroup 做业务分组

你可以把自定义指标统一挂在一个业务域下面:

java 复制代码
Counter c = getRuntimeContext()
  .getMetricGroup()
  .addGroup("MyMetrics")
  .counter("myCounter");

也可以用 key/value 形式:

java 复制代码
Counter c = getRuntimeContext()
  .getMetricGroup()
  .addGroup("biz", "payment")
  .counter("failures");

4.2 System Scope:决定"这条指标属于哪个 Job/Task/Operator"

Flink 允许你配置各种 scope 模板,例如 operator 级:

metrics.scope.operator 默认类似:

<host>.taskmanager.<tm_id>.<job_name>.<operator_name>.<subtask_index>

你也可以改成包含 task_name、job_id 等。这里有个生产级注意点:如果你把 tm_id/job_id 去掉,可能导致同名 job 并跑时指标冲突,监控数据会乱。所以想"短一点",也要保留至少一个足够唯一的字段(比如 <job_id>)。

4.3 User Variables 与 labels/tags:把同一个算子按业务维度拆开看

你可以给一个 Transformation 加自定义变量:

java 复制代码
fooSource = execEnv.fromSource(kafkaSource, wm, "KafkaSource-Foo")
  .addMetricVariable("table_name", "Foo");

barSource = execEnv.fromSource(kafkaSource, wm, "KafkaSource-Bar")
  .addMetricVariable("table_name", "Bar");

如果你的 reporter 支持 labels/tags,就能把这些变量映射成标签,做出更细的维度分析(同一个算子实例按 table_name 拆开看)。

5. 系统指标怎么用:按"排障剧本"抓重点

你贴的系统指标非常全,我建议生产上抓这几类核心面板,定位速度会快很多。

5.1 Checkpoint 相关(大状态必看)

JobManager 侧关键指标:

  • lastCheckpointDuration
  • lastCheckpointSize / lastCheckpointFullSize
  • numberOfInProgressCheckpoints
  • numberOfFailedCheckpoints

Task 侧定位根因的两把刀:

  • checkpointStartDelayNanos:barrier 到达延迟,高通常是背压或数据倾斜
  • checkpointAlignmentTime:对齐耗时,高通常是 aligned checkpoint + 背压/倾斜

排障套路:

  1. startDelay 高:先看上游背压与数据倾斜
  2. alignment 高:考虑 unaligned(但别忘了它不治根因),同时查慢通道/慢下游

5.2 背压与吞吐(判断"为什么慢")

Task 指标里最有用的一组:

  • isBackPressured
  • busyTimeMsPerSecond
  • idleTimeMsPerSecond
  • backPressuredTimeMsPerSecond(以及 soft/hard)
  • numRecordsInPerSecond / numRecordsOutPerSecond

判断逻辑很直观:

  • idle 高:没数据或上游慢
  • backpressured 高:下游顶不住或外部系统慢
  • busy 高但吞吐低:CPU/GC/状态访问/序列化可能是瓶颈

Task 侧:

  • mailboxQueueSize
  • mailboxLatencyMs
  • mailboxMailsPerSecond

如果 mailboxLatency 持续升高,常见原因是:checkpoint/定时器/异步回调等控制面动作堆积,作业会表现为"明明 CPU 不满但就是卡"。

5.4 Shuffle / Network(网络缓冲是否不够)

优先看 Default shuffle service(Netty)这套:

  • Status.Shuffle.Netty.*(memory segments / used memory 等)
  • RequestedMemoryUsage(超过 100% 吞吐容易明显掉)
  • input/output queue length/size

RequestedMemoryUsage 经常 > 100%,要么加网络内存,要么降低 buffer pool 配置,否则吞吐会明显受影响。

5.5 状态访问延迟与状态大小(RocksDB/ForSt/大状态定位神器)

如果你怀疑状态访问慢(尤其 RocksDB/ForSt),看这些直方图:

  • valueStateGetLatency / valueStateUpdateLatency
  • mapStateGetLatency / mapStatePutLatency
  • 以及对应的 key/value size:valueStateGetKeySize / valueStateGetValueSize ...

这两组一起用特别猛:

  • 延迟高 + valueSize 大:典型"大 value 导致序列化/IO 重"
  • 延迟高 + keySize 大:可能是 key 设计不合理或拼接过长
  • 延迟高但 size 不大:更像 cache miss、磁盘/网络、线程池拥塞

5.6 ForSt 解耦状态:文件缓存命中率(很关键)

ForSt 专属:

  • forst.fileCache.hit/miss
  • usedBytes
  • lru.evict / lru.loadback

命中率低 + loadback 高,通常就是"远端读太多",要么加 cache,要么改访问模式(优先异步 State API V2 的方式)。

5.7 Changelog 与 Async State Processing(新能力面板)

  • Changelog 上传队列、upload latencies、materialization 成败与耗时
  • Async state processing 的 in-flight、blocking key 数量

这些指标能直接回答两个关键问题:

  • "changelog 把我卡住了吗?"
  • "异步状态是不是因为某些 key 被 blocking 形成热点?"

6. 两个"高成本开关":只建议调试时开启

6.1 端到端延迟 LatencyMarker(latencyTrackingInterval)

开启后 sources 会周期性发 LatencyMarker,形成 source→operator 的延迟分布直方图。粒度越高,直方图数量可能呈平方增长(parallelism 高时特别吓人),对性能有显著影响,建议仅用于定位延迟问题。

6.2 Keyed State 延迟/大小采样

两个开关:

  • state.latency-track.keyed-state-enabled
  • state.size-track.keyed-state-enabled

采样参数:

  • *.sample-interval(默认 100,越小越准但越贵)
  • *.history-size(默认 128,越大越占内存但统计更稳)

建议:线上长期关,出现疑难杂症时短时间开启,配合直方图快速定位。

7. REST API 查询指标:最实用的"无 UI 排障方式"

常用端点(路径形式):

  • /jobmanager/metrics
  • /taskmanagers/<taskmanagerid>/metrics
  • /jobs/<jobid>/metrics
  • /jobs/<jobid>/vertices/<vertexid>/subtasks/<subtaskindex>

两种典型用法:

列出可用指标:

  • GET /jobmanager/metrics

取指定指标值:

  • GET /taskmanagers/ABCDE/metrics?get=metric1,metric2

聚合查询(min/max/avg/sum):

  • GET /taskmanagers/metrics?get=metric1,metric2&agg=min,max

注意:metric name 里如果有特殊字符需要 URL 转义,例如 + 要写成 %2B

8. Dashboard(Web UI)里怎么挑指标看

在 Job 页面点 Metrics 标签:

  • Task 级指标一般是:<subtask_index>.<metric_name>
  • Operator 级指标一般是:<subtask_index>.<operator_name>.<metric_name>

建议你固定三套面板习惯:

  1. 吞吐 + 背压(numRecordsIn/Out、busy/idle/backpressured)
  2. checkpoint(lastCheckpointDuration、startDelay、alignment)
  3. 状态(state access latency + key/value size;ForSt cache hit/miss)

只要这三套在,90% 的性能与稳定性问题都能很快收敛到根因。

相关推荐
中山六匹马1 小时前
2026中山B2B网站建设:如何结合GEO优化提升企业竞争力
大数据·网络·人工智能
AIArchivist2 小时前
坚守医疗本质,科技赋能未来|清华长庚肝胆AI与悦尔AI的共赢之路
大数据·人工智能·科技
AIArchivist2 小时前
牙髓干细胞微创治疗牙周炎:临床突破、患者价值、产业前景与未来展望
大数据
OpenCSG2 小时前
什么是模型管理平台?从大模型治理走向企业级OPC平台
大数据·人工智能·opencsg
sdyeswlw2 小时前
案例直击|一二三物联网 2025 三大经典项目,解锁物联赋能新场景
大数据·网络·人工智能
m0_528749003 小时前
git如何用
大数据·elasticsearch·搜索引擎
忙碌5443 小时前
OpenTelemetry实战指南:构建云原生全链路可观测性体系
ios·flink·apache·iphone
金融小师妹3 小时前
基于NLP情绪分析与机器学习预测:避险情绪升温,黄金价格触及5200关键阈值
大数据·人工智能·机器学习·重构