Spark流式自定义指标

时间:2015-09-29 12:17:23

标签: java apache-spark jmx spark-streaming codahale-metrics

我正在开发一个Spark Streaming程序,该程序检索Kafka流,对流进行非常基本的转换,然后将数据插入到DB(如果相关的话,则为voltdb)。 我试图测量我向DB插入行的速率。我认为metrics可能很有用(使用JMX)。但是,我无法找到如何向Spark添加自定义指标。我查看了Spark的源代码,并找到了this thread,但它对我来说并不起作用。我还在conf.metrics文件中启用了JMX接收器。什么不起作用是我没有通过JConsole看到我的自定义指标。

有人可以解释如何添加自定义指标(最好通过JMX)来激发流媒体?或者如何测量我的数据库(特别是VoltDB)的插入速率? 我在Java 8中使用spark。

5 个答案:

答案 0 :(得分:15)

在深入了解source code后,我发现了如何添加自己的自定义指标。它需要3件事:

  1. 创建我自己的自定义source。有点像this
  2. 在spark metrics.properties文件中启用Jmx接收器。我使用的具体行是:*.sink.jmx.class=org.apache.spark.metrics.sink.JmxSink为所有实例启用JmxSink
  3. 在SparkEnv指标系统中注册我的自定义源。可以看到如何做的示例here - 我之前看过这个链接但是错过了注册部分,这使我无法在JVisualVM中实际看到我的自定义指标
  4. 我仍然在努力实现如何实际计算插入VoltDB的数量,因为代码在执行程序上运行,但这是一个不同主题的主题:)

    我希望这会有助于其他人

答案 1 :(得分:5)

Groupon有一个名为spark-metrics的库,它允许您在执行程序上使用简单的(类似Codahale)API,并将结果整理回驱动程序中并自动在Spark的现有指标注册表中注册。然后,当您根据Spark docs配置指标接收器时,这些会随着Spark的内置指标自动导出。

答案 2 :(得分:3)

从VoltDB中插入基于插入的行,使用累加器 - 然后从你的驱动程序中创建一个监听器 - 可能是这样的东西让你入门

sparkContext.addSparkListener(new SparkListener() {
  override def onStageCompleted(stageCompleted: SparkListenerStageCompleted) {
    stageCompleted.stageInfo.accumulables.foreach { case (_, acc) => {

在这里你可以访问那些组合累加器的行,然后你可以发送到你的接收器..

答案 3 :(得分:2)

这是一个很好的教程,涵盖了使用Graphite设置Spark的MetricsSystem所需的所有设置。这应该是诀窍:

http://www.hammerlab.org/2015/02/27/monitoring-spark-with-graphite-and-grafana/

答案 4 :(得分:0)

下面是Java中的一个有效示例。
已通过StreaminQuery进行了测试(不幸的是,StreaminQuery在Spark 2.3.1之前没有像StreamingContext这样的ootb指标)。

步骤:

Source类的同一包中定义自定义来源

package org.apache.spark.metrics.source;

import com.codahale.metrics.Gauge;
import com.codahale.metrics.MetricRegistry;
import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.spark.sql.streaming.StreamingQueryProgress;

/**
 * Metrics source for structured streaming query.
 */
public class StreamingQuerySource implements Source {
    private String appName;
    private MetricRegistry metricRegistry = new MetricRegistry();
    private final Progress progress = new Progress();

    public StreamingQuerySource(String appName) {
        this.appName = appName;
        registerGuage("batchId", () -> progress.batchId());
        registerGuage("numInputRows", () -> progress.numInputRows());
        registerGuage("inputRowsPerSecond", () -> progress.inputRowsPerSecond());
        registerGuage("processedRowsPerSecond", () -> progress.processedRowsPerSecond());
    }

    private <T> Gauge<T> registerGuage(String name, Gauge<T> metric) {
        return metricRegistry.register(MetricRegistry.name(name), metric);
    }

    @Override
    public String sourceName() {
        return String.format("%s.streaming", appName);
    }


    @Override
    public MetricRegistry metricRegistry() {
        return metricRegistry;
    }

    public void updateProgress(StreamingQueryProgress queryProgress) {
        progress.batchId(queryProgress.batchId())
                .numInputRows(queryProgress.numInputRows())
                .inputRowsPerSecond(queryProgress.inputRowsPerSecond())
                .processedRowsPerSecond(queryProgress.processedRowsPerSecond());
    }

    @Data
    @Accessors(fluent = true)
    private static class Progress {
        private long batchId = -1;
        private long numInputRows = 0;
        private double inputRowsPerSecond = 0;
        private double processedRowsPerSecond = 0;
    }
}

在创建SparkContext之后立即注册源

    querySource = new StreamingQuerySource(getSparkSession().sparkContext().appName());
    SparkEnv.get().metricsSystem().registerSource(querySource);

更新StreamingQueryListener.onProgress(event)中的数据

  querySource.updateProgress(event.progress());

配置metrics.properties

*.sink.graphite.class=org.apache.spark.metrics.sink.GraphiteSink
*.sink.graphite.host=xxx
*.sink.graphite.port=9109
*.sink.graphite.period=10
*.sink.graphite.unit=seconds

# Enable jvm source for instance master, worker, driver and executor
master.source.jvm.class=org.apache.spark.metrics.source.JvmSource
worker.source.jvm.class=org.apache.spark.metrics.source.JvmSource
driver.source.jvm.class=org.apache.spark.metrics.source.JvmSource
executor.source.jvm.class=org.apache.spark.metrics.source.JvmSource

石墨出口器中的样品输出(映射为普罗米修斯格式)

streaming_query{application="local-1538032184639",model="model1",qty="batchId"} 38
streaming_query{application="local-1538032184639",model="model1r",qty="inputRowsPerSecond"} 2.5
streaming_query{application="local-1538032184639",model="model1",qty="numInputRows"} 5
streaming_query{application="local-1538032184639",model=model1",qty="processedRowsPerSecond"} 0.81