Пользовательские метрики потоковой передачи Spark
Я работаю над программой Spark Streaming, которая извлекает поток Кафки, выполняет очень базовое преобразование в потоке, а затем вставляет данные в БД (voltdb, если это актуально). Я пытаюсь измерить скорость, с которой я вставляю строки в БД. Я думаю показатели может быть полезно (используя JMX). Однако я не могу найти, как добавить пользовательские метрики в Spark. Я посмотрел исходный код Spark, а также нашел этой теме однако это не работает для меня. Я также включен JMX тонет в конф.файл метрик. Что не работает, так это то, что я не вижу свои пользовательские метрики с JConsole.
может кто-нибудь объяснить, как добавить пользовательские метрики (желательно через JMX) в Spark streaming? Или альтернативно, как измерить скорость вставки в мой DB (в частности, VoltDB)? Я использую spark с Java 8.
5 ответов
Ok после копания через исходный код Я нашел, как добавить свои собственные метрики. Требуется 3 вещи:
- создать свой собственный источник. Вроде как этой
- включить приемник Jmx в метриках spark.файл свойств. Конкретная строка, которую я использовал:
*.sink.jmx.class=org.apache.spark.metrics.sink.JmxSink
которые включают JmxSink для всех экземпляров - зарегистрируйте мой пользовательский источник в системе метрик SparkEnv. Пример как это сделать можно видел здесь - Я действительно просматривал эту ссылку раньше, но пропустил часть регистрации, которая помешала мне увидеть мои пользовательские показатели в JVisualVM
Я все еще борюсь с тем, как на самом деле подсчитать количество вставок в VoltDB, потому что код работает на исполнителях, но это тема для другой темы :)
Я надеюсь, что это поможет другим
Groupon имеют библиотеку под названием spark-metrics
это позволяет использовать простой (Codahale-подобный) API на ваших исполнителях и сопоставлять результаты в драйвере и автоматически регистрироваться в существующем реестре метрик Spark. Затем они автоматически экспортируются вместе со встроенными метриками Spark при настройке приемника метрик в соответствии с Spark docs.
чтобы вставить строки из на основе вставок из VoltDB, используйте аккумуляторы - а затем из вашего драйвера вы можете создать прослушиватель-может быть, что-то вроде этого, чтобы вы начали
sparkContext.addSparkListener(new SparkListener() {
override def onStageCompleted(stageCompleted: SparkListenerStageCompleted) {
stageCompleted.stageInfo.accumulables.foreach { case (_, acc) => {
здесь у вас есть доступ к этим строкам комбинированных аккумуляторов, а затем вы можете отправить в раковину..
вот отличный учебник, который охватывает все setps вам нужно настроить MetricsSystem СПАРК с графитом. Это должно сделать трюк:
http://www.hammerlab.org/2015/02/27/monitoring-spark-with-graphite-and-grafana/
Ниже приведен рабочий пример на Java.
Он протестирован с StreaminQuery
(к сожалению StreaminQuery
не имеет показателей ootb, таких как StreamingContext
пока искра 2.3.1).
действия:
определите пользовательский источник в том же пакете 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(событие)
querySource.updateProgress(event.progress());
метрики конфигурации.свойства
*.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