我有一个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
}
答案 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
功能中退回状态,因此您可以在外面使用进一步处理。