Spark Structured Streaming: 自维护(任意)状态流的“超时”(Timeout)问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/bluishglc/article/details/80844327

此“超时”非彼“超时”

在我们开始这篇文章之前,我们必须要先弄清除一下问题:为什么流的上的状态会有“超时”问题?超时机制是为什么样的业务场景而设计的?通常情形下,人们一种直白的想法是:某种状态在长时间没有得到来自新数据的更新时,我们可以认为这个状态是“超时”了,它应该不复存在了,应该永远的被移除掉。然而遗憾的时是,Spark对于“状态”以及“超时”是另外一种理解:

Spark认为既然流是没有边界的,那么以某个key产生的支流(就是mapGroupsWithState或者flatMapGroupsWithState维护的有状态的流)上的“状态”(一个Key对应的GroupState实例)也将是“不眠不休”的,即永不会消亡,而在GroupState上对State对象的移除动作并不是对当前“状态”的一种终结操作,新的State对象会在新数据的驱动下被重新创建出来,同样的,对于GroupState上的“超时”,它也不是像我们前面预想的那样:是代表着一种由于流的“终结”而触发的“绝响”(超时过后,这条支流及其状态将不复存在),而也只是永不消亡的GroupState实例上的某个中间状态!同样的,超时处理完后,还是会有新的数据进来,新的State对象还是会在新数据的驱动下被重新创建出来。

所以,如果你的业务逻辑是存在一系列的“事件”,这些“事件”前后关联,形成一种session,OK,你自然会想到以session的ID为Key为每个session构建一个自维护的State来维持这个session, 但如果这个session会终结的,那么你这样做就会出问题。首先,如前所述,这个构建出来的状态是永远不会消亡的,它会一直存在而不会被资源回收,更重要的是,如果你是寄希望通过超时来触发session的终结操作,则这将可能永远不会被触发,因为在Spark上,所有自维护(任意)状态的流,超时都是在有新的数据进入时检测时间差来判定的,当你的session发出最后一个“事件”后,不会再新的事件发生让spark来触发超时检测了!

基于处理时间和事件和事件时间的超时处理的异同

对于自维护的状态,超时既可以基于处理时间(i.e. GroupStateTimeout.ProcessingTimeTimeout) 又可以基于事件时间 (i.e. GroupStateTimeout.EventTimeTimeout),如果选择了基于”处理时间“,则超时的duration是通过GroupState.setTimeoutDuration来设定的,但是超时并非是严格地发生在设定的duration的时间点上,而是在当刚刚超过duration的那次trigger发生时,所以说timeout并没有一个严格的“上限”(也就是最晚发生的时间,相对应的“下限“是指最早的发生时间,这个时间是刚好在duration的时间点上),举个例子:如果流上在最近一段时间没有任何数据,则整个负责维护状态的函数根本不会被触发,也就不会执行任何超时检测,直到有新的数据到达,这样有可能会导致在很长时间之后才会触发超时处理,而并不是在规定的那个超时时间点上触发的,这就是所谓的timeout并没有严格的“上限”的意思。

如果选择的是基于“事件时间”,首先要开启基于事件时间框架,即必须在查询中使用Dataset.withWatermark(),然后需要在GroupState中使用GroupState.setTimeoutTimestamp()设定超时,setTimeoutTimestamp有两类版本,一类是设定一个固定时间戳,另一类是在一个指定的时间戳上再指定一个duration, 前者适用于那些有明确超时时间点的场景,后者适用于那些在某个最新的事件时间上再追加一个duration的场景。但是有一点是非常重要和清楚的,就是这个每次设定的超时时间戳是不能晚于watermark的!因为Spark在基于”事件时间“ 判定超时的原则就是:当且仅当watermark超过(晚于)了设定的timeout!某种意义上,我们可以认为watermark是当前“状态实例”(不是GroupState,而是它包裹的那个State对象)认定”存活“的一个”开始“的时间界限,timeout是当前”状态实例“认定”存活“的一个”截止“的时间界限,如果开始的时间比截止的时间还要晚,说明这个状态实例超时了!最后,在基于”事件时间“时,对于实际的超时时间也是没有一个准确的”上限“的,这和基于“事件时间”的超时判定的原因是一样的,因为watermark也是在流中有新数据时才会被触发更新,进而计算超时的时间。

猜你喜欢

转载自blog.csdn.net/bluishglc/article/details/80844327
今日推荐