Spark结构化流式Kafka微批计数

时间:2018-08-07 16:50:15

标签: apache-spark apache-kafka spark-structured-streaming

我正在使用Spark结构化流传输来读取Kafka主题中的记录;我打算计算Spark readstream

中每个“微型批次”中收到的记录数

这是一个片段:

val kafka_df = sparkSession
  .readStream
  .format("kafka")
  .option("kafka.bootstrap.servers", "host:port")
  .option("subscribe", "test-count")
  .load()

我从文档中了解到,当启动streamingQuery(下一个)时,kafka_df将被延迟评估,并且在评估时,它会保留一个微型批处理。因此,我认为在 topic 上先进行groupBy,然后再进行count即可。

赞:

val counter = kafka_df
             .groupBy("topic")
             .count()

现在要评估所有这些,我们需要一个streaminQuery(可以说是一个控制台接收器查询)以将其打印在控制台上。这就是我看到问题的地方。 aggregate数据帧(例如kafka_df)上的streamingQuery仅适用于outputMode 完成/更新 ,而不适用于 附加

这实际上意味着,streamingQuery报告的计数是累积的。

赞:

 val counter_json = counter.toJSON   //to jsonify 
 val count_query = counter_json
                   .writeStream.outputMode("update")
                   .format("console")
                   .start()          // kicks of lazy evaluation
                   .awaitTermination()  

在受控设置中,其中:
 实际已发布记录:1500
 实际收到的微型批次:3
a实际收到的记录:1500

每个微批处理的数量应该为 500 ,所以我希望(希望)查询能够打印到控制台:

  

topic:测试计数
     数量:500
  主题:测试计数
  数量:500
  主题:测试计数
  数:500

但事实并非如此。它实际上会打印:

  

topic:测试计数
     数量:500
  主题:测试计数
  数量:1000
  主题:测试计数
  数:1500

我了解这是由于'outputMode'完成/更新(累积)

我的问题:是否可以准确获取Spark-Kafka结构化流的每个微批计数?

从文档中,我发现了有关水印方法(以支持追加):

val windowedCounts = kafka_df
                    .withWatermark("timestamp", "10 seconds")
                    .groupBy(window($"timestamp", "10 seconds", "10       seconds"), $"topic")
                    .count()

 val console_query = windowedCounts
                    .writeStream
                    .outputMode("append")
                    .format("console")
                    .start()
                    .awaitTermination()

但是此console_query的结果不准确,并且显示出来是不正确的。

TL; DR-对于准确计数Spark-Kafka微批处理中的记录的任何想法,将不胜感激。

2 个答案:

答案 0 :(得分:1)

如果要使用Kafka在结构化流应用程序中使用每个触发器仅处理特定数量的记录,请使用选项maxOffsetsPerTrigger

val kafka_df = sparkSession
  .readStream
  .format("kafka")
  .option("kafka.bootstrap.servers", "host:port")
  .option("subscribe", "test-count")
  .option("maxOffsetsPerTrigger", 500)
  .load()

答案 1 :(得分:0)

“ TL; DR-关于准确计数Spark-Kafka微批处理中的记录的任何想法,将不胜感激。”

您可以使用StreamingQueryListenerScalaDocs)计算从Kafka获取的记录。

这使您可以打印出从已订阅的Kafka主题收到的确切行数。 onQueryProgress API在每个微批处理期间都会被调用,并且包含有关查询的很多个有用的元信息。如果没有数据流入查询,则每10秒调用一次onQueryProgress。下面是一个简单的示例,它打印出输入消息的数量。

spark.streams.addListener(new StreamingQueryListener() {
    override def onQueryStarted(queryStarted: QueryStartedEvent): Unit = {}

    override def onQueryTerminated(queryTerminated: QueryTerminatedEvent): Unit = {}

    override def onQueryProgress(queryProgress: QueryProgressEvent): Unit = {
      println("NumInputRows: " + queryProgress.progress.numInputRows)
    }
  })

如果您要验证结构化流查询的性能,通常最好留意以下两个指标:

  • queryProgress.progress.inputRowsPerSecond
  • queryProgress.progress.processedRowsPerSecond

如果输入高于已处理,则可能会增加工作资源或降低最大限制(通过减少readStream选项maxOffsetsPerTrigger)。如果处理得更高,则可能要增加此限制。