Java Spark流式定制度量

Java Spark流式定制度量,java,apache-spark,jmx,spark-streaming,codahale-metrics,Java,Apache Spark,Jmx,Spark Streaming,Codahale Metrics,我正在开发一个Spark流媒体程序,它检索一个Kafka流,对该流进行非常基本的转换,然后将数据插入到一个DB(voltdb,如果相关的话)。 我试图测量向数据库插入行的速率。我认为这可能很有用(使用JMX)。但是,我找不到如何向Spark添加自定义指标。我看过Spark的源代码,也发现它不适合我。我还在conf.metrics文件中启用了JMX接收器。不起作用的是,我看不到JConsole的自定义指标 有人能解释一下如何将自定义指标(最好是通过JMX)添加到spark流媒体吗?或者,如何测量我

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

有人能解释一下如何将自定义指标(最好是通过JMX)添加到spark流媒体吗?或者,如何测量我的插入速率到我的DB(特别是VoltDB)?
我将spark与Java 8一起使用。

这是一个优秀的教程,涵盖了使用Graphite设置spark度量系统所需的所有SETP。这应该可以做到:


好的,在深入研究之后,我找到了如何添加自己的自定义指标。它需要3件事:

  • 创造我自己的习惯。有点像
  • 在spark metrics.properties文件中启用Jmx接收器。我使用的具体行是:
    *.sink.jmx.class=org.apache.spark.metrics.sink.JmxSink
    ,它为所有实例启用JmxSink
  • 在SparkEnv metrics系统中注册我的自定义源。可以看到一个如何做的示例-我以前确实查看过此链接,但错过了注册部分,这使我无法在JVisualVM中实际查看自定义度量
  • 我仍然在为如何计算插入VoltDB的次数而挣扎,因为代码在执行器上运行,但这是另一个主题:)


    我希望这将有助于其他人

    基于VoltDB的插入插入行,使用累加器-然后从驱动程序创建一个侦听器-也许类似的东西可以帮助您开始

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

    在这里,您可以访问这些行组合累加器,然后可以发送到接收器。

    Groupon有一个名为的库,允许您在执行器上使用简单(类似于Codahale)API,并将结果整理回驱动程序中,并自动注册到Spark的现有度量注册表中。然后,当您按照配置度量接收器时,这些将与Spark的内置度量一起自动导出。

    下面是Java中的一个工作示例。
    它是用
    StreaminQuery
    测试的(不幸的是
    StreaminQuery
    在Spark 2.3.1之前没有类似
    StreamingContext
    的ootb指标)

    步骤:

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

    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;
        }
    }
    
    *.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
    
    更新StreamingQueryListener.onProgress(事件)中的数据

    Config metrics.properties

    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;
        }
    }
    
    *.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
    
    石墨导出器中的样本输出(映射到普罗米修斯格式)


    谢谢Erik的回复,非常有用!但是您是否在应用程序代码中添加了自己的度量?我说的不是spark已经监控过的东西,而是其他的东西,比如每个分区中的行插入VoltDB的速率?(或代码中的任何其他自定义度量)。我正在努力在我的应用程序中实现自定义度量。我最终为每个执行者收集度量,并将其发送到Graphana,然后汇总那里的所有信息。不过,听众的想法很酷:)@Gideon你能详细说明一下吗?你说你放弃了正常的指标,自己做了工作,还是你让他们工作了?我没有放弃正常的指标。我在Spark executors上添加了一些自己的自定义指标。问题是,对于这些自定义指标,我需要聚合结果(基本上是对来自不同执行器的累加器求和),所以我所做的是将来自每个Spark执行器的数据发送到Graphana并聚合结果。您是否知道如何计算来自执行器的数据?我有一个类似的用例,我写HTTP端点,我想从执行者那里数一堆东西,但计数器不会移动。这实际上是很久以前的事了,但据我记忆所及,我从执行者那里用codahale度量发送了我的度量,他们有一个Graphite reporter,我只是用graphiteAh总结了所有东西好的,谢谢你的回复。我的用例有点不同,编写我自己的源代码并尝试将事件发送到内部度量工具。编写您自己的度量与我的答案完全相同,问题在于从执行者处发送它们?注册我的自定义度量时,我发现MetricSystem由
    private[spark]
    指定,我无法在MetricsSystem的主函数中注册我的自定义度量,您如何解决这个问题?谢谢,我显然不再纠结于这个问题了,但是,很高兴知道有一些有用的库可以提供这类东西。谢谢你的提示:)
    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