Я пишу библиотеку для интеграции Apache Spark с настраиваемой средой. Я реализую как пользовательские потоковые источники, так и потоковые писатели.
Некоторые из источников, которые я разрабатываю, не подлежат восстановлению, по крайней мере, после краха приложения. Если приложение перезагружается, ему необходимо перезагрузить все данные. Поэтому мы хотели бы, чтобы пользователи не задавали явно опцию checkpointLocation. Но если опция не указана, мы видим следующую ошибку:
org.apache.spark.sql.AnalysisException: checkpointLocation must be specified either through option("checkpointLocation", ...) or SparkSession.conf.set("spark.sql.streaming.checkpointLocation", ...);
Однако, если я использую вывод консольного потока, все работает нормально.
Есть ли способ получить такое же поведение?
Примечание. Мы используем интерфейсы Spark v2 для наших потоковых считывателей/писателей.
Журнал искры:
18/06/29 16:36:48 INFO SharedState: Setting hive.metastore.warehouse.dir ('null') to the value of spark.sql.warehouse.dir ('file:/C:/mydir/spark-warehouse/').
18/06/29 16:36:48 INFO SharedState: Warehouse path is 'file:/C:/mydir/spark-warehouse/'.
18/06/29 16:36:48 INFO StateStoreCoordinatorRef: Registered StateStoreCoordinator endpoint
org.apache.spark.sql.AnalysisException: checkpointLocation must be specified either through option("checkpointLocation", ...) or SparkSession.conf.set("spark.sql.streaming.checkpointLocation", ...);
at org.apache.spark.sql.streaming.StreamingQueryManager$$anonfun$3.apply(StreamingQueryManager.scala:213)
at org.apache.spark.sql.streaming.StreamingQueryManager$$anonfun$3.apply(StreamingQueryManager.scala:208)
at scala.Option.getOrElse(Option.scala:121)
at org.apache.spark.sql.streaming.StreamingQueryManager.createQuery(StreamingQueryManager.scala:207)
at org.apache.spark.sql.streaming.StreamingQueryManager.startQuery(StreamingQueryManager.scala:299)
at org.apache.spark.sql.streaming.DataStreamWriter.start(DataStreamWriter.scala:296)
...
18/06/29 16:36:50 INFO SparkContext: Invoking stop() from shutdown hook
Вот как я запускаю потоковое задание:
spark.readStream().format("mysource").load()
.writeStream().format("mywriter").outputMode(OutputMode.Append()).start();
Все работает отлично, вместо этого, если, например, я запускаю:
spark.readStream().format("mysource").load()
.writeStream().format("console").outputMode(OutputMode.Append()).start();
Я не могу предоставить полный код записи данных. Во всяком случае, я сделал что-то вроде этого:
class MySourceProvider extends DataSourceRegister with StreamWriteSupport {
def createStreamWriter(queryId: String, schema: StructType, mode: OutputMode, options: DataSourceOptions): StreamWriter = {
new MyStreamWriter(...)
}
def shortName(): String = {
"mywriter"
}
}
class MyStreamWriter(...) extends StreamWriter {
def abort(epochId: Long, messages: Array[WriterCommitMessage]): Unit = {}
def commit(epochId: Long, messages: Array[WriterCommitMessage]): Unit = {}
def createWriterFactory(): DataWriterFactory[Row] = {
new MyDataWriterFactory()
}
}
Вам нужно добавить checkpointLocation в свой код
("checkpointLocation", "/tmp/vaquarkhan/checkpoint"). //<- контрольная точка
Пример :
import org.apache.spark.sql.streaming.{OutputMode, Trigger}
import scala.concurrent.duration._
val q = records.
writeStream.
format("console").
option("truncate", false).
option("checkpointLocation", "/tmp/vaquarkhan/checkpoint"). // <-- checkpoint directory
trigger(Trigger.ProcessingTime(10.seconds)).
outputMode(OutputMode.Update).
start
Обратившись к вашему вопросу, у вас есть три варианта:
.option("startOffsets", "latest")//чтение данных с конца потока
самое раннее - начните чтение в начале потока. Это исключает данные, которые уже были удалены из Kafka, потому что они были старше, чем период хранения (данные "устаревших").
last - начать сейчас, обрабатывать только новые данные, которые поступают после начала запроса.
для каждого раздела - указать точное смещение для начала для каждого раздела, что позволяет точно контролировать то, где должна начинаться обработка. Например, если мы хотим точно определить, где остановилась какая-либо другая система или запрос, тогда этот параметр можно использовать.
Если имя каталога для местоположения контрольной точки невозможно найти, createQuery сообщает об исключении AnalysisException.
checkpointLocation must be specified either through option("checkpointLocation", ...) or SparkSession.conf.set("spark.sql.streaming.checkpointLocation", ...)
Ниже приведен искровой код apache:
private def createQuery(
userSpecifiedName: Option[String],
userSpecifiedCheckpointLocation: Option[String],
df: DataFrame,
extraOptions: Map[String, String],
sink: BaseStreamingSink,
outputMode: OutputMode,
useTempCheckpointLocation: Boolean,
recoverFromCheckpointLocation: Boolean,
trigger: Trigger,
triggerClock: Clock): StreamingQueryWrapper = {
var deleteCheckpointOnStop = false
val checkpointLocation = userSpecifiedCheckpointLocation.map { userSpecified =>
new Path(userSpecified).toUri.toString
}.orElse {
df.sparkSession.sessionState.conf.checkpointLocation.map { location =>
new Path(location, userSpecifiedName.getOrElse(UUID.randomUUID().toString)).toUri.toString
}
}.getOrElse {
if (useTempCheckpointLocation) {
// Delete the temp checkpoint when a query is being stopped without errors.
deleteCheckpointOnStop = true
Utils.createTempDir(namePrefix = s"temporary").getCanonicalPath
} else {
throw new AnalysisException(
"checkpointLocation must be specified either " +
"""through option("checkpointLocation", ...) or """ +
s"""SparkSession.conf.set("${SQLConf.CHECKPOINT_LOCATION.key}", ...)""")
}
}