Java Spark流式定制度量
我正在开发一个Spark流媒体程序,它检索一个Kafka流,对该流进行非常基本的转换,然后将数据插入到一个DB(voltdb,如果相关的话)。 我试图测量向数据库插入行的速率。我认为这可能很有用(使用JMX)。但是,我找不到如何向Spark添加自定义指标。我看过Spark的源代码,也发现它不适合我。我还在conf.metrics文件中启用了JMX接收器。不起作用的是,我看不到JConsole的自定义指标 有人能解释一下如何将自定义指标(最好是通过JMX)添加到spark流媒体吗?或者,如何测量我的插入速率到我的DB(特别是VoltDB)?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与Java 8一起使用。这是一个优秀的教程,涵盖了使用Graphite设置spark度量系统所需的所有SETP。这应该可以做到:
好的,在深入研究之后,我找到了如何添加自己的自定义指标。它需要3件事:
*.sink.jmx.class=org.apache.spark.metrics.sink.JmxSink
,它为所有实例启用JmxSink我希望这将有助于其他人基于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