避免多个流式查询

时间:2018-02-13 02:01:59

标签: apache-spark spark-structured-streaming

我有一个结构化的流媒体查询,它汇入Kafka。此查询具有复杂的聚合逻辑。

我想将此查询的输出DF汇总到多个Kafka主题,每个主题在不同的“密钥”列上进行分区。我不想为每个不同的Kafka主题设置多个Kafka接收器,因为这意味着要运行多个流式查询 - 每个Kafka主题一个,特别是因为我的聚合逻辑很复杂。

问题:

  1. 有没有办法将结构化流式传输查询的结果输出到多个Kafka主题,每个主题都有不同的键列,但不必执行多个流式查询?

  2. 如果没有,那么级联多个查询是否有效,以便第一个查询执行复杂聚合并将输出写入Kafka,然后其他查询只读取第一个查询的输出并将其主题写入卡夫卡因此避免再次进行复杂的聚合?

  3. 提前感谢您的帮助。

3 个答案:

答案 0 :(得分:4)

所以答案就是盯着我的眼睛。它也有记录。下方链接。

可以从单个查询中写入多个Kafka主题。如果要编写的数据框具有名为“topic”的列(以及“key”和“value”列),则会将行的内容写入该行中的主题。这会自动生效。因此,您唯一需要弄清楚的是如何生成该列的值。

记录在案 - https://spark.apache.org/docs/latest/structured-streaming-kafka-integration.html#writing-data-to-kafka

答案 1 :(得分:3)

我也在寻找解决这个问题的方法,在我看来,这不一定是卡夫卡沉没。我想在接收器1中写一个数据帧的记录,而在接收器2中写一些其他记录(取决于某些条件,在2个流查询中不读取相同的数据两次)。 当前,按照当前的实现,这似乎是不可能的(DataSource.scala中的createSink()方法提供对单个接收器的支持)。

但是,在Spark 2.4.0中有一个新的api:foreachBatch()将为数据帧微批处理提供句柄,该微批处理可用于缓存数据帧,写入不同的接收器或在取消缓存aagin之前进行多次处理。 像这样:

streamingDF.writeStream.foreachBatch { (batchDF: DataFrame, batchId: Long) =>
  batchDF.cache()
  batchDF.write.format(...).save(...)  // location 1
  batchDF.write.format(...).save(...)  // location 2
  batchDF.uncache()
}

现在此功能可在databricks运行时中使用: https://docs.databricks.com/spark/latest/structured-streaming/foreach.html#reuse-existing-batch-data-sources-with-foreachbatch

修改15年11月15日: 现在可以在Spark 2.4.0(https://issues.apache.org/jira/browse/SPARK-24565

中使用

答案 2 :(得分:0)

开箱即用的结构化流媒体无法进行单次读取和多次写入。唯一的方法是实现将写入多个主题的自定义接收器。

每当你调用dataset.writeStream().start()时,spark就会启动一个从源(readStream())读取并写入接收器(writeStream())的新流。

即使您尝试级联,它也会创建两个独立的流,每个流有一个源和一个接收器。换句话说,它将读取,处理和写入数据两次:

Dataset df = <aggregation>; 
StreamingQuery sq1 = df.writeStream()...start(); 
StreamingQuery sq2 = df.writeStream()...start();

有一种方法可以在Spark流中缓存读取数据,但此选项尚不适用于结构化流式传输。