Spark 2.2 a introduit une source de streaming structuré de Kafka. Si je comprends bien, il s'appuie sur le répertoire de point de contrôle HDFS pour stocker les décalages et garantir une livraison de message "exactement une fois".
Mais les anciens quais (comme https://blog.cloudera.com/blog/2017/06/offset-management-for-Apache-kafka-with-Apache-spark-streaming/ ) disent que = Spark Les points de contrôle de streaming ne sont pas récupérables entre les applications ou Spark mises à niveau et donc pas très fiables. Comme solution, il existe une pratique pour prendre en charge le stockage de décalages dans le stockage externe qui prend en charge les transactions comme MySQL ou RedshiftDB.
Si je veux stocker des décalages de Kafka vers une base de données transactionnelle, comment puis-je obtenir le décalage d'un lot de flux structuré?
Auparavant, cela peut être fait en castant RDD en HasOffsetRanges
:
val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
Mais avec la nouvelle API de streaming, j'ai un Dataset
de InternalRow
et je ne trouve pas un moyen facile de récupérer les décalages. L'API Sink n'a que la méthode addBatch(batchId: Long, data: DataFrame)
et comment puis-je supposer obtenir un décalage pour l'ID de lot donné?
Pertinent Spark Le fil de discussion de la liste de diffusion DEV est ici .
Résumé:
Spark Streaming prendra en charge l'obtention de décalages dans les futures versions (> 2.2.0). Billet JIRA à suivre - https://issues-test.Apache.org/jira/browse/SPARK-18258
Pour Spark <= 2.2.0, vous pouvez obtenir des décalages pour le lot donné en lisant un json dans le répertoire checkpoint (l'API n'est pas stable, donc soyez prudent):
val checkpointRoot = // read 'checkpointLocation' from custom sink params
val checkpointDir = new Path(new Path(checkpointRoot), "offsets").toUri.toString
val offsetSeqLog = new OffsetSeqLog(sparkSession, checkpointDir)
val endOffset: Map[TopicPartition, Long] = offsetSeqLog.get(batchId).map { endOffset =>
endOffset.offsets.filter(_.isDefined).map { str =>
JsonUtilsWrapper.jsonToOffsets(str.get.json)
}
}
/**
* Hack to access private API
* Put this class into org.Apache.spark.sql.kafka010 package
*/
object JsonUtilsWrapper {
def offsetsToJson(partitionOffsets: Map[TopicPartition, Long]): String = {
JsonUtils.partitionOffsets(partitionOffsets)
}
def jsonToOffsets(str: String): Map[TopicPartition, Long] = {
JsonUtils.partitionOffsets(str)
}
}
Ce endOffset
contiendra l'offset jusqu'à pour chaque sujet/partition. Obtenir les décalages de démarrage est problématique, car vous devez lire le répertoire du point de contrôle "commit". Mais généralement, vous ne vous souciez pas des décalages de début, car le stockage des décalages de fin est suffisant pour un redémarrage fiable du travail Spark.
Veuillez noter que vous devez également stocker l'ID de lot traité dans votre stockage. Spark peut réexécuter le lot ayant échoué avec le même identifiant de lot dans certains cas, assurez-vous donc d'initialiser un récepteur personnalisé avec le dernier identifiant de lot traité (que vous devez lire à partir du stockage externe) et ignorer tout lot avec id <latestProcessedBatchId. Btw, l'ID de lot n'est pas unique entre les requêtes, vous devez donc stocker l'ID de lot pour chaque requête séparément.
Spark 2.2 a introduit une source de streaming structuré de Kafka. Si je comprends bien, il s'appuie sur le répertoire de point de contrôle HDFS pour stocker les décalages et garantir une livraison de message "exactement une fois".
Correct.
Chaque déclencheur Spark Le streaming structuré enregistre les décalages dans le répertoire offset
à l'emplacement du point de contrôle (défini à l'aide de l'option checkpointLocation
ou spark.sql.streaming.checkpointLocation
Spark ou assignée au hasard) qui est censée garantir que les décalages sont traités au plus une fois . La fonction est appelée Écrire les journaux à venir .
L'autre répertoire de l'emplacement du point de contrôle est le répertoire commits
pour les lots de streaming terminés avec un seul fichier par lot (avec un nom de fichier comme identifiant de lot).
Citant la documentation officielle dans Fault Tolerance Semantics :
Pour y parvenir, nous avons conçu les sources de streaming structuré, les puits et le moteur d'exécution pour suivre de manière fiable la progression exacte du traitement afin qu'il puisse gérer tout type d'échec par redémarrage et/ou retraitement. Chaque source de diffusion en continu est supposée avoir des décalages (similaires à Kafka décalages ou numéros de séquence Kinesis) pour suivre la position de lecture dans le flux. Le moteur utilise des points de contrôle et des journaux d'avance pour enregistrer la plage de décalage des données en cours de traitement dans chaque déclencheur. Les récepteurs de diffusion en continu sont conçus pour être idempotents pour gérer le retraitement. Ensemble, en utilisant des sources rejouables et des récepteurs idempotents, la diffusion structurée peut garantir une sémantique de bout en bout exactement une fois en cas d'échec.
Chaque fois qu'un déclencheur est exécuté, StreamExecution
vérifie les répertoires et "calcule" quels décalages ont déjà été traités. Cela vous donne au moins une fois sémantique et exactement une fois au total.
Mais les anciens documents (...) disent que Spark Les points de contrôle de streaming ne sont pas récupérables entre les applications ou Spark mises à niveau et donc pas très fiables).
Il y avait une raison pour laquelle vous les appeliez "vieux", n'était pas là?
Ils se réfèrent à l'ancien et (à mon avis) mort Spark Streaming qui a gardé non seulement les décalages mais le code de requête entier qui a conduit à des situations où le point de contrôle était presque inutilisable, par exemple lorsque vous changez le code .
Les temps sont désormais révolus et le Streaming Structuré est plus prudent sur le moment et le point de contrôle.
Si je veux stocker des décalages de Kafka vers une base de données transactionnelle, comment puis-je obtenir le décalage d'un lot de flux structuré?
Une solution pourrait être d'implémenter ou d'utiliser d'une manière ou d'une autre MetadataLog interface utilisée pour gérer le point de contrôle de décalage. Cela pourrait fonctionner.
comment puis-je supposer obtenir un décalage pour l'ID de lot donné?
Ce n'est pas possible actuellement.
Ma compréhension est que vous ne pourrez pas le faire car la sémantique du streaming vous est cachée. Vous devriez simplement ne pas gérer cette "chose" de bas niveau appelée compensations que Spark Structured Streaming utilise pour offrir exactement une fois garantit.
Citant Michael Armbrust de son discours à Spark Summit Traitement de flux facile, évolutif et tolérant aux pannes avec le streaming structuré dans Apache Spark :
vous ne devriez pas avoir à vous soucier du streaming
et plus loin dans l'exposé (sur la diapositive suivante) :
vous devez écrire des requêtes simples & Spark doit mettre à jour en permanence la réponse
Il existe un moyen d'obtenir des compensations (de n'importe quelle source, Kafka y compris) en utilisant StreamingQueryProgress
qui vous pouvez intercepter en utilisant StreamingQueryListener et onQueryProgress
callback.
onQueryProgress (événement: QueryProgressEvent): Unité Appelé en cas de mise à jour de l'état (taux d'ingestion mis à jour, etc.)
Avec StreamingQueryProgress
vous pouvez accéder à la propriété sources
avec SourceProgress qui vous donne ce que vous voulez.
Streaming Dataset avec Kafka a offset
comme l'un des champ . Vous pouvez simplement interroger tous les décalages dans la requête et les enregistrer dans JDBC Sink