我正在使用提供here in spark streaming documentation的策略来提交kafka本身。我的流程是这样的: 主题A - > Spark Stream [foreachRdd进程 - >发送到主题b]将偏移量提交给主题A
JavaInputDStream<ConsumerRecord<String, Request>> kafkaStream = KafkaUtils.createDirectStream(
streamingContext,
LocationStrategies.PreferConsistent(),
ConsumerStrategies.<String, Request>Subscribe(inputTopics, kafkaParams)
);
kafkaStream.foreachRDD(rdd -> {
OffsetRange[] offsetRanges = ((HasOffsetRanges) rdd).offsetRanges();
rdd.foreachPartition(
consumerRecords -> {
OffsetRange o = offsetRanges[TaskContext.get().partitionId()];
System.out.println(String.format("$s %d %d $d", o.topic(), o.partition(), o.fromOffset(), o.untilOffset()));
consumerRecords.forEachRemaining(record -> doProcess(record));
});
((CanCommitOffsets) kafkaStream.inputDStream()).commitAsync(offsetRanges);
}
);
因此,让我们说RDD从主题A获取10个事件,并且在处理每个事件时,我向主题B发送新事件。现在假设其中一个响应失败。现在我不想将该特定偏移量提交给主题A.主题A和B具有相同数量的分区N.因此每个RDD应该从同一分区消耗。什么是继续处理的最佳策略?如何重置流以尝试从主题A处理这些事件,直到成功为止?我知道如果我不能继续处理该分区而不提交,因为这会自动移动偏移量并且不会再次处理失败的记录。
我不知道如何使stream / rdd继续尝试仅为该分区处理相同的消息,而其他分区/ rdd可以继续工作。如果我从特定的RDD中抛出异常,我的工作会发生什么。它会失败吗?我需要手动重启吗?对于普通消费者,您可以重试/恢复,但我不确定Streaming会发生什么。
答案 0 :(得分:0)
这是我提出的,它接受输入数据,然后使用输出主题发送请求。必须在foreach循环内创建生成器,否则spark将尝试序列化并将其发送给所有worker。请注意,响应是异步发送的。这意味着我在这个系统中使用至少一个语义。
kafkaStream.foreachRDD(rdd -> {
OffsetRange[] offsetRanges = ((HasOffsetRanges) rdd.rdd()).offsetRanges();
rdd.foreachPartition(
partition -> {
OffsetRange o = offsetRanges[TaskContext.get().partitionId()];
System.out.println(String.format("%s %d %d %d", o.topic(), o.partition(), o.fromOffset(), o.untilOffset()));
// Print statements in this section are shown in the executor's stdout logs
KafkaProducer<String, MLMIOutput> producer = new KafkaProducer(producerConfig(o.partition()));
partition.forEachRemaining(record -> {
System.out.println("request: "+record.value());
Response data = new Response …
// As as debugging technique, users can write to DBFS to verify that records are being written out
// dbutils.fs.put("/tmp/test_kafka_output",data,true)
ProducerRecord<String, Response> message = new ProducerRecord(outputTopic, null, data);
Future<RecordMetadata> result = producer.send(message);
try {
RecordMetadata metadata = result.get();
System.out.println(String.format("offset='$d' partition='%d' topic='%s'timestamp='$d",
metadata.offset(),metadata.partition(),metadata.topic(),metadata.timestamp()));
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
});
producer.close();
});
((CanCommitOffsets) kafkaStream.inputDStream()).commitAsync(offsetRanges);
}
);