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 侧关键指标:
lastCheckpointDurationlastCheckpointSize/lastCheckpointFullSizenumberOfInProgressCheckpointsnumberOfFailedCheckpoints
Task 侧定位根因的两把刀:
checkpointStartDelayNanos:barrier 到达延迟,高通常是背压或数据倾斜checkpointAlignmentTime:对齐耗时,高通常是 aligned checkpoint + 背压/倾斜
排障套路:
- startDelay 高:先看上游背压与数据倾斜
- alignment 高:考虑 unaligned(但别忘了它不治根因),同时查慢通道/慢下游
5.2 背压与吞吐(判断"为什么慢")
Task 指标里最有用的一组:
isBackPressuredbusyTimeMsPerSecondidleTimeMsPerSecondbackPressuredTimeMsPerSecond(以及 soft/hard)numRecordsInPerSecond/numRecordsOutPerSecond
判断逻辑很直观:
- idle 高:没数据或上游慢
- backpressured 高:下游顶不住或外部系统慢
- busy 高但吞吐低:CPU/GC/状态访问/序列化可能是瓶颈
5.3 Mailbox(Flink 内部"调度队列"是否堵了)
Task 侧:
mailboxQueueSizemailboxLatencyMsmailboxMailsPerSecond
如果 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/valueStateUpdateLatencymapStateGetLatency/mapStatePutLatency等- 以及对应的 key/value size:
valueStateGetKeySize/valueStateGetValueSize...
这两组一起用特别猛:
- 延迟高 + valueSize 大:典型"大 value 导致序列化/IO 重"
- 延迟高 + keySize 大:可能是 key 设计不合理或拼接过长
- 延迟高但 size 不大:更像 cache miss、磁盘/网络、线程池拥塞
5.6 ForSt 解耦状态:文件缓存命中率(很关键)
ForSt 专属:
forst.fileCache.hit/missusedByteslru.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-enabledstate.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>
建议你固定三套面板习惯:
- 吞吐 + 背压(numRecordsIn/Out、busy/idle/backpressured)
- checkpoint(lastCheckpointDuration、startDelay、alignment)
- 状态(state access latency + key/value size;ForSt cache hit/miss)
只要这三套在,90% 的性能与稳定性问题都能很快收敛到根因。