如何处理州

时间:2016-05-26 15:42:42

标签: scala session apache-spark spark-streaming

我有一个sessionization用例。由于in-memory,我保留了会话mapWithstate(),并为每个传入日志更新它们。当会话结束时,使用特定日志发出信号,我想要检索它并将其从State中删除。

我遇到的问题是我无法在每个remove()的末尾检索并删除(batch)我的会话,因为检索发生在updateFunction()之外并且在其中删除,即一旦删除会话无法检索,如果会话结束,则不应再有日志,不再有key s。

我仍然可以检索已结束的会话,但“死”会话的数量会升级,从而产生一个完整的异常(“State - 溢出”),如果不加以检查将会威胁到系统本身。这个解决方案是不可接受的。

由于它似乎是一个常见的用例,我想知道是否有人提出了解决方案?

修改

以下示例代码:

def mapWithStateContainer(iResultParsing: DStream[(String, SessionEvent)]) = {
  val lStateSpec = StateSpec.function(stateUpdateFunction _).timeout(Seconds(TIMEOUT)

  val lResultMapWithState: DStream[(String, Session)] = 
        iResultParsing.mapWithState(lStateSpec).stateSnapshots()

  val lClosedSession: DStream[(String, Session)] = 
        lResultMapWithState.filter(_._2.mTimeout)

    //ideally remove here lClosedSession from the state
}

private def stateUpdateFunction(iKey: String,
                                iValue: Option[SessionEvent],
                                iState: State[Session]): Option[(String, Session)] = {
  var lResult = None: Option[(String, Session)]

  if (iState.isTimingOut()) {
    val lClosedSession = iState.get()
    lClosedSession.mTimeout = true

    lResult = Some(iKey, lClosedSession)
  } else if (iState.exists) {
      val lUpdatedSession = updateSession(lCurrentSession, iValue)
      iState.update(lUpdatedSession)

      lResult = Some(iKey, lUpdatedSession)

      // we wish to remove the lUpdatedSession from the state once retrieved with lResult
      /*if (lUpdatedSession.mTimeout) {
         iState.remove()
         lResult = None
       }*/
    } else {
       val lInitialState = initSession(iValue)
       iState.update(lInitialState)

       lResult = Some(iKey, lInitialState)
    }

    lResult
}

private def updateSession(iCurrentSession: Session, 
                          iNewData: Option[SessionEvent]): Session = {
    //user disconnects manually
    if (iNewData.get.mDisconnection) {
        iCurrentSession.mTimeout = true
    }

    iCurrentSession
}

1 个答案:

答案 0 :(得分:0)

您可以将更新后的状态作为MapWithStateRDD.stateSnapshot操作的返回值返回,而不是调用mapWithState。这样,最终状态始终在您的有状态DStream之外可用。

这意味着您可以:

else if (iState.exists) {
  val lUpdatedSession = updateSession(lCurrentSession, iValue)
  iState.update(lUpdatedSession)

  if (lUpdatedSession.mTimeout) {
    iState.remove()
  }

  Some(iKey, lUpdatedSession)
}

现在将图表更改为:

val lResultMapWithState = iResultParsing
                            .mapWithState(lStateSpec)
                            .filter { case (_, session) => session.mTimeout }

现在状态正在内部删除,但由于您已从StateSpec功能中退回状态,因此您可以在外面使用进一步处理。