【Flink metric(1)】Flink指标系统的系统性知识:获取metric以及注册自己的metric

本文我们通过官网来整体了解下flink 指标系统的系统性支持

 

本文主要关注:

  • 如何注册自定义指标,如何进行更新指标数据
  • 指标定义的层级:即指标的scope
  • 简单介绍,指标如何报告给外部系统、有哪些系统指标
  • 指标如何通过REST API获取
  • 在flink UI上创建Dashboard的方法

 

Flink exposes a metric system that allows gathering and exposing metrics to external systems.

flink 暴露了一个指标系统,可以收集和暴露指标给外部系统。

一. Registering metrics:向flink注册新自己的metrics

1. 注册metrics

任何继承了RichFunction 的用户函数,都可以通过调用:getRuntimeContext().getMetricGroup() ,来访问flink的metric system。方法返回的MetricGroup可以用来创建和注册新的指标。

 

2. Metric types:指标类型

flink支持 Counters, Gauges, Histograms and Meters.等四种指标类型。

2.1. Counter

计数器 (Counter) 用于计数某个指标。

  • 可以使用 inc()/inc(long n)dec()/dec(long n) 方法来增加或减少当前值。
  • 可以通过在 MetricGroup 上调用 counter(String name) 来创建并注册一个计数器。
public class MyMapper extends RichMapFunction<String, String> {
  private transient Counter counter;

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

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

你也可以自己实现counter。

public class MyMapper extends RichMapFunction<String, String> {
  private transient Counter counter;

  @Override
  public void open(Configuration config) {
    this.counter = getRuntimeContext()
      .getMetricGroup()
      .counter("myCustomCounter", new CustomCounter());
  }

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

 

2.2. Gauge

可以提供任何数据类型,要使用Gauge你必须要实现Gauge接口,可以返回任何类型。

public class MyMapper extends RichMapFunction<String, String> {
  private transient int valueToExpose = 0;

  @Override
  public void open(Configuration config) {
    getRuntimeContext()
      .getMetricGroup()
      .gauge("MyGauge", new Gauge<Integer>() {
        @Override
        public Integer getValue() {
          return valueToExpose;
        }
      });
  }

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

 

2.3. Histogram(ing)

直方图(Histogram)用于测量长整型值的分布情况。

可以通过在 MetricGroup 上调用 histogram(String name, Histogram histogram) 来注册一个直方图。

public class MyMapper extends RichMapFunction<Long, Long> {
  private transient Histogram histogram;

  @Override
  public void open(Configuration config) {
    this.histogram = getRuntimeContext()
      .getMetricGroup()
      .histogram("myHistogram", new MyHistogram());
  }

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

ing

 

2.4. Meter

一个 Meter 用于测量平均吞吐量。

  • 可以使用 markEvent() 方法注册一个事件的发生。同时发生多个事件可以使用 markEvent(long n) 方法注册。
  • 在 MetricGroup 上调用 meter(String name, Meter meter) 来注册一个 Meter。

 

二. Scope:指标作用域

每个度量指标都被分配了一个标识符和一组键值对,用于报告该度量指标。
这个标识符基于三个组件:在注册度量指标时的用户定义名称,一个可选的用户定义作用域,以及一个系统提供的作用域。

例如,如果 A.B 是系统作用域,C.D 是用户作用域,E 是名称,那么度量指标的标识符将是 A.B.C.D.E。

你可以通过在 Flink 配置文件中设置 metrics.scope.delimiter 键来配置标识符使用的分隔符(默认为 .)。

 

1. User Scope

你可以通过调用 MetricGroup#addGroup(String name),MetricGroup#addGroup(int name),或者 MetricGroup#addGroup(String key, String value) 来定义用户作用域。

我们通过 MetricGroup#getMetricIdentifier 和 MetricGroup#getScopeComponents 方法返回的内容。

counter = getRuntimeContext()
  .getMetricGroup()
  .addGroup("MyMetrics")
  .counter("myCounter");

counter = getRuntimeContext()
  .getMetricGroup()
  .addGroup("MyMetricsKey", "MyMetricsValue")
  .counter("myCounter");

 

2. System Scope ing

 

3. User Variables

你可以通过调用 MetricGroup#addGroup(String key, String value) 来定义一个用户变量。

这个方法会影响 MetricGroup#getMetricIdentifier、MetricGroup#getScopeComponents 和 MetricGroup#getAllVariables() 返回的内容。

counter = getRuntimeContext()
  .getMetricGroup()
  .addGroup("MyMetricsKey", "MyMetricsValue")
  .counter("myCounter");

 

三. Reporter ing

Flink 支持用户将 Flink 的各项运行时指标发送给外部系统。

 

四. System metrics ing

默认情况下,Flink会收集多个度量指标,这些指标能够深入了解当前的状态。

 

五. REST API integration

度量指标可以通过监控REST API查询。以下是可用端点列表及其示例JSON响应。

序号metric类型API
1特定实体的metric- /jobmanager/metrics
- /taskmanagers/<taskmanagerid>/metrics
- /jobs/<jobid>/metrics
- /jobs/<jobid>/vertices/<vertexid>/subtasks/<subtaskindex>
2实体的聚合metric- /taskmanagers/metrics
- /jobs/metrics
- /jobs/<jobid>/vertices/<vertexid>/subtasks/metrics
- /jobs/<jobid>/vertices/<vertexid>/jm-operator-metrics
3实体子集上聚合的metric- /taskmanagers/metrics?taskmanagers=A,B,C
- /jobs/metrics?jobs=D,E,F
- /jobs/<jobid>/vertices/<vertexid>/subtasks/metrics?subtask=1,2,3

 

六. Dashboard integration

可以在仪表板中可视化每个任务或操作符收集的度量指标。在作业的主页面上,选择“Metrics”选项卡。在顶部图表中选择一个任务后,您可以使用“添加度量指标”下拉菜单选择要显示的度量指标。如下图:

  • 任务度量指标列出为<子任务索引>.<度量名称>。
  • 操作符度量指标列出为 <子任务索引>.<操作符名称>.<度量名称>

在这里插入图片描述

  • 每个度量指标将显示为单独的图表,其中 x 轴代表时间,y 轴表示测量值。
  • 所有图表每隔10秒自动更新一次,在导航到其他页面时仍会继续更新。
  • 可视化的度量指标数量没有限制,但是只有数值型度量指标可以被可视化显示。

 

<think> 我们参考用户提供的引用内容,特别是引用[1]和引用[3],来回答如何将Flink任务的Metric指标上报到Kafka。 引用[1]提到滴滴使用了自研的flink-metrics-kafka,采用推送(Push)方式,周期性将指标推送到Kafka topic。 引用[3]则给出了配置Flink metrics reporter的示例(虽然示例中是GraphiteReporter,但原理类似)。 因此,我们可以通过以下步骤实现: 1. 自定义一个实现`org.apache.flink.metrics.MetricReporter`接口的类,特别是`KafkaReporter`。 2. 在flink-conf.yml中配置使用这个自定义的reporter。 3. 启动Flink任务,指标会自动上报到Kafka。 由于Flink社区没有提供官方的Kafka reporter,所以需要自定义。下面我们详细说明如何实现。 ### 自定义Kafka Metric Reporter实现步骤 #### 1. 创建自定义MetricReporter 需要实现`MetricReporter`接口,并至少实现以下方法: - `open(MetricConfig config)`: 初始化Kafka生产者等。 - `close()`: 关闭资源。 - `notifyOfAddedMetric(Metric metric, String metricName, MetricGroup group)`: 当有新的Metric被添加时,将其加入收集列表。 - `notifyOfRemovedMetric(Metric metric, String metricName, MetricGroup group)`:Metric被移除时,将其从收集列表中移除。 同时,我们需要一个定时器,定期将收集到的指标发送到Kafka。 #### 2. 实现代码框架 ```java import org.apache.flink.metrics.*; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class KafkaMetricsReporter implements MetricReporter, CharacterFilter { private final Map<Gauge<?>, String> gauges = new HashMap<>(); private final Map<Counter, String> counters = new HashMap<>(); private final Map<Meter, String> meters = new HashMap<>(); private final Map<Histogram, String> histograms = new HashMap<>(); private ScheduledExecutorService scheduler; private KafkaProducer<String, String> producer; private String topic; @Override public void open(MetricConfig config) { // 获取配置中的Kafka broker地址和topic String brokers = config.getString("brokers", "localhost:9092"); topic = config.getString("topic", "flink-metrics"); Properties props = new Properties(); props.put("bootstrap.servers", brokers); props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); producer = new KafkaProducer<>(props); // 启动定时任务 scheduler = new ScheduledThreadPoolExecutor(1); long period = config.getLong("period", 10000L); // 默认10秒 scheduler.scheduleAtFixedRate(this::report, period, period, TimeUnit.MILLISECONDS); } @Override public void close() { scheduler.shutdown(); producer.close(); } @Override public void notifyOfAddedMetric(Metric metric, String metricName, MetricGroup group) { String metricIdentifier = group.getMetricIdentifier(metricName, this); synchronized (this) { if (metric instanceof Counter) { counters.put((Counter) metric, metricIdentifier); } else if (metric instanceof Gauge) { gauges.put((Gauge<?>) metric, metricIdentifier); } else if (metric instanceof Meter) { meters.put((Meter) metric, metricIdentifier); } else if (metric instanceof Histogram) { histograms.put((Histogram) metric, metricIdentifier); } } } @Override public void notifyOfRemovedMetric(Metric metric, String metricName, MetricGroup group) { synchronized (this) { if (metric instanceof Counter) { counters.remove(metric); } else if (metric instanceof Gauge) { gauges.remove(metric); } else if (metric instanceof Meter) { meters.remove(metric); } else if (metric instanceof Histogram) { histograms.remove(metric); } } } private void report() { // 构建一个包含所有指标的JSON对象 JSONObject metricsJson = new JSONObject(); synchronized (this) { for (Map.Entry<Gauge<?>, String> entry : gauges.entrySet()) { metricsJson.put(entry.getValue(), entry.getKey().getValue()); } for (Map.Entry<Counter, String> entry : counters.entrySet()) { metricsJson.put(entry.getValue(), entry.getKey().getCount()); } for (Map.Entry<Meter, String> entry : meters.entrySet()) { metricsJson.put(entry.getValue(), entry.getKey().getRate()); } for (Map.Entry<Histogram, String> entry : histograms.entrySet()) { metricsJson.put(entry.getValue(), entry.getKey().getStatistics().getMean()); } } producer.send(new ProducerRecord<>(topic, metricsJson.toString())); } @Override public String filterCharacters(String input) { // 过滤掉可能影响指标名称的非法字符 return input.replaceAll("[^a-zA-Z0-9_:]", "_"); } } ``` #### 3. 打包并放入Flink的lib目录 将上述代码编译打包成JAR文件,然后放入Flink集群每个节点的`lib`目录下。 #### 4. 配置flink-conf.yaml 在`flink-conf.yaml`中添加以下配置: ```yaml metrics.reporter.kafka.class: com.yourcompany.KafkaMetricsReporter metrics.reporter.kafka.brokers: kafka-broker1:9092,kafka-broker2:9092 # Kafka集群地址 metrics.reporter.kafka.topic: flink-metrics # 目标topic metrics.reporter.kafka.period: 10000 # 上报间隔,单位毫秒 ``` #### 5. 启动Flink任务 当启动Flink任务时,指标就会按照配置的时间间隔上报到Kafka。 ### 注意事项 1. **Kafka依赖**:自定义的reporter需要引入Kafka客户端的依赖,建议使用`flink-metrics-core`和`kafka-clients`。 2. **异常处理**:在定时任务中捕获异常,避免线程终止。 3. **性能影响**:频繁上报可能对Flink任务性能造成影响,需根据实际情况调整上报周期。 4. **指标格式**:上述示例使用JSON格式,也可以根据需求使用其他格式(如Prometheus格式)。 > 引用[1]提到滴滴自研了flink-metrics-kafka,说明在生产环境中这种方案是可行的[^1]。引用[5]中提到在反序列化时进行指标统计,但这里我们讨论的是系统级别的Metric上报,所以采用Reporter方式更合适[^5]。 --- §§相关问题§§ 1. Flink Metrics系统支持哪些类型的指标? 2. 如何自定义Flink Metric指标? 3. 除了Kafka,Flink Metrics还可以上报到哪些系统? </think> ### Flink任务Metrics指标上报到Kafka的方法 #### 1. **核心实现原理** Flink通过**MetricReporter**机制实现指标上报。需要自定义实现`MetricReporter`接口,将指标推送到Kafka(Push模式)[^1]。流程如下: ```mermaid graph LR A[Flink任务运行时] --> B[Metric系统收集指标] B --> C[自定义KafkaReporter] C --> D[序列化指标数据] D --> E[写入Kafka Topic] ``` #### 2. **完整实现步骤** ##### (1) 创建自定义Reporter(Java实现) ```java import org.apache.flink.metrics.*; import org.apache.kafka.clients.producer.*; public class KafkaMetricsReporter implements MetricReporter { private KafkaProducer<String, String> producer; private String topic; @Override public void open(MetricConfig config) { // 初始化Kafka生产者 Properties props = new Properties(); props.put("bootstrap.servers", config.getString("brokers", "localhost:9092")); props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); this.producer = new KafkaProducer<>(props); this.topic = config.getString("topic", "flink-metrics"); } @Override public void notifyOfAddedMetric(Metric metric, String name, MetricGroup group) { // 指标添加时触发 String metricName = group.getMetricIdentifier(name); ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); scheduler.scheduleAtFixedRate(() -> { String value = metric instanceof Gauge ? ((Gauge<?>) metric).getValue().toString() : "0"; producer.send(new ProducerRecord<>(topic, metricName, value)); }, 0, 10, TimeUnit.SECONDS); // 每10秒上报一次 } @Override public void close() { producer.close(); // 关闭Kafka连接 } } ``` ##### (2) 在`flink-conf.yaml`中配置 ```yaml metrics.reporter.kafka.class: com.yourpackage.KafkaMetricsReporter metrics.reporter.kafka.brokers: kafka1:9092,kafka2:9092 # Kafka集群地址 metrics.reporter.kafka.topic: flink-metrics-topic # 目标Topic metrics.reporter.kafka.interval: 10 SECONDS # 上报间隔 ``` ##### (3) 打包部署 1. 将包含`KafkaMetricsReporter`的JAR放入Flink的`lib/`目录 2. 重启TaskManager和JobManager #### 3. **指标数据格式优化** 建议使用JSON格式增强可读性: ```json { "timestamp": 1672531200000, "metric": "SourceOperator_numRecordsIn", "value": 24560, "tags": { "job": "OrderProcessing", "task": "Source_Kafka" } } ``` #### 4. **生产环境注意事项** 1. **资源隔离**:为Metrics设置独立Kafka Topic,避免影响业务数据 2. **序列化优化**:使用Avro或Protobuf替代JSON提高效率 3. **错误处理**:添加重试机制应对Kafka暂时不可用 ```java producer.send(record, (metadata, exception) -> { if (exception != null) logger.error("发送失败", exception); }); ``` 4. **安全认证**:配置SASL/SSL(如需要): ```yaml metrics.reporter.kafka.security.protocol: SASL_SSL metrics.reporter.kafka.sasl.jaas.config: org.apache.kafka.common.security.plain.PlainLoginModule required username="user" password="pass"; ``` #### 5. **验证与监控** 1. **消费测试**: ```bash kafka-console-consumer.sh --bootstrap-server kafka:9092 \ --topic flink-metrics-topic --from-beginning ``` 2. **监控指标**: - `kafka.producer:record-send-rate`:上报速率 - `kafka.producer:request-latency-avg`:Kafka响应延迟 > 如引用[1]所述,滴滴采用类似方案实现了生产级指标监控[^1]。引用[5]展示了在Source算子中直接统计指标的方法,但Reporter方式更通用[^5]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

roman_日积跬步-终至千里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值