Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/apache-kafka/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache spark Spark结构化流中的密钥在完成';GroupStateTimeout.ProcessingTimeout()';_Apache Spark_Apache Kafka_Spark Structured Streaming - Fatal编程技术网

Apache spark Spark结构化流中的密钥在完成';GroupStateTimeout.ProcessingTimeout()';

Apache spark Spark结构化流中的密钥在完成';GroupStateTimeout.ProcessingTimeout()';,apache-spark,apache-kafka,spark-structured-streaming,Apache Spark,Apache Kafka,Spark Structured Streaming,我正在编写结构化流的代码,其中我从Kafka队列订阅数据,并将这些原始数据写回Hbase。在这笔交易之间,我必须满足以下要求: 流中的数据必须在2小时的窗口内消除重复,即,每当有新密钥的数据进入时,密钥应在内存中保留2小时,并且这2小时内的所有重复数据不得发送到Hbase 如果密钥的新记录已处于状态,但值已更改,则应将更新后的记录发送到Hbase,并且该密钥应在此之后在内存中保留2小时 无法确定数据可能到达的时间有多晚,任何传入的数据都将满足上述任何条件 由于条件2和3,我不能使用spark提供

我正在编写结构化流的代码,其中我从Kafka队列订阅数据,并将这些原始数据写回Hbase。在这笔交易之间,我必须满足以下要求:

  • 流中的数据必须在2小时的窗口内消除重复,即,每当有新密钥的数据进入时,密钥应在内存中保留2小时,并且这2小时内的所有重复数据不得发送到Hbase
  • 如果密钥的新记录已处于状态,但值已更改,则应将更新后的记录发送到Hbase,并且该密钥应在此之后在内存中保留2小时
  • 无法确定数据可能到达的时间有多晚,任何传入的数据都将满足上述任何条件
  • 由于条件2和3,我不能使用spark提供的即时重复数据消除,因为应用水印会删除比条件3更旧的数据

    所以为了解决这个问题,我采用了“任意状态全处理” 参考:

    我的代码如下:

    从卡夫卡读取的代码

      val kafkaIpStream = spark.readStream.format("kafka")
          .option("kafka.bootstrap.servers", kafkaBroker)
          .option("subscribe", topic)
          .option("startingOffsets", "earliest")
          .load()
    
    要消除重复的代码

        val kafkaStream = kafkaIpStream.selectExpr("cast (key as String)", "cast (value as String)")
          .withColumn("ts", split($"key", "/")(1))
          .selectExpr("key as rowkey", "ts", "value as val")
          .withColumn("isValid", validationUDF($"rowkey", $"ts", $"val"))
          .as[inputTsRecord]
          .groupByKey(_.rowkey)
          .flatMapGroupsWithState(OutputMode.Update(), GroupStateTimeout.ProcessingTimeTimeout())(updateStateAccrossRecords)
          .toDF("rowkey", "ts", "val", "isValid")
    
    重复数据消除功能

    case class inputTsRecord(rowkey: String, ts: String, `val`: String, isValid: String)
      case class state(rowkey: String, `val`: String, insertTimestamp: Long)
    
      def updateStateAccrossRecords(rowKey: String, inputRows: Iterator[inputTsRecord], oldState: GroupState[state]): Iterator[inputTsRecord] = {
    
        inputRows.toSeq.toIterator.flatMap { iprow =>
    
          println("received data for " + iprow.rowkey)
    
          if (oldState.hasTimedOut) {
    
              println("State timed out")
    
              oldState.remove()
              Iterator()
            }
          else if (oldState.exists) {
    
            println("State exists for " + iprow.rowkey)
    
              val timeDuration=((((System.currentTimeMillis / 1000)-oldState.get.insertTimestamp)/60)/60) 
    
              println("State not timed out for " + iprow.rowkey)
    
    
              println("Duration passed " + timeDuration)
    
              val updatedState = state(iprow.rowkey, iprow.`val`, (System.currentTimeMillis / 1000))
              val isValChanged = if (updatedState.`val` == oldState.get.`val`) false  else true
    
              if (isValChanged) {
    
                println("value changed for " + iprow.rowkey)
                oldState.update(updatedState)
                oldState.setTimeoutDuration("2 hours")
    
                Iterator(iprow)
              } else {
                if (timeDuration >= 2)
                {
                   println("removing state for " + iprow.rowkey)
                  oldState.remove()
                }
                 println("value not changed for " + iprow.rowkey)
                Iterator()
              }
    
    
    
          } else {
    
            println("State does not exists for " + iprow.rowkey)
    
            val newState = state(iprow.rowkey, iprow.`val`, (System.currentTimeMillis / 1000))
            oldState.update(newState)
            oldState.setTimeoutDuration("2 hours")
    
            Iterator(iprow)
          }
    
        }
      }
    
    
    现在的问题是:

  • 即使将超时指定为2小时的处理超时 密钥在指定时间[通过日志检查]后不会过期
  • 密钥是唯一的,即理想情况下,只有一个条目用于 应用程序整个生命周期的密钥,除非存在 重复
  • 因此,状态最终包含所有将 随着流的进行,会导致内存问题
  • 密钥只有在2小时后收到数据时才会过期 由于以下代码而到达
  • 流正在接收连续数据
  • 据我所知,在流上使用GroupStateTimeout.ProcessingTimeout()时,密钥应在到达指定处理时间后过期

    我错过了什么

    谢谢你的帮助

     if (timeDuration >= 2){
                   println("removing state for " + iprow.rowkey)
                  oldState.remove()
                }