作者:草小诚(wellsmile@foxmail.com)
转载请注原文地址:https://blog.youkuaiyun.com/cxcjoker7894/article/details/85774764
本文介绍state定时清零,如欲监控失败自动重启请移步【Spark Streaming 监控失败后自动重启】
业务实现中,监听目录后,在任务里用 updateStateByKey 方法储存了当前的计算数值(state),但是实际的数据要求 每天清零,也就是一直都仅显示当天的计算数值。
Spark Streaming 似乎没有直接提供这样的功能,那么除了写系统脚本每天重启 Spark Job,有没有更优雅的解决办法呢?
哈,当然是有的,利用 while True 和 awaitTerminationOrTimeout 函数就可以实现了,各语言的这个方法都在 StreamingContext 包(类)里:
Scala 文档 StreamingContext 包下的 awaitTerminationOrTimeout 方法(搜索)
Java 文档 StreamingContext 类下的 awaitTerminationOrTimeout 方法(搜索)
Python 文档 pyspark.streaming.StreamingContext.awaitTerminationOrTimeout
方法的解释是:执行后会等待任务的结束,如果结束会返回 True,如果过程中出现异常会抛出,可以设置 timeout 时长,设置后如果限定时长内没有等到任务结束,就返回 False。
所以不难看出,我们只要设置 timeout 时长至每天的零点,然后等待该方法返回 False 再去重新 start 任务就好了。因为返回 False 就意味着这个方法一直等到了零点任务都没有结束。
下面以python为例,先获取当前时间到明天零点的秒数,作为 timeout 时长:
import datetime
def get_reset_seconds():
# 明天0点的时间字符串
date_second = (datetime.datetime.now() + datetime.timedelta(days=1)).strftime("%Y-%m-%d") + ' 00:00:00'
# 明天0点的时间戳(秒)
reset_ts = int(datetime.datetime.strptime(date_second, "%Y-%m-%d %H:%M:%S").timestamp())
# 当前时间到明天0点的差值(秒)
return reset_ts - int(datetime.datetime.now().timestamp())
将任务的创建与启停用 while True 包起来,每次循环为一天,每次重启都重新调用上面的方法设置 timeout 时长,即使是首次启动也无需担心:
from pyspark import SparkContext
from pyspark.streaming import StreamingContext
while True:
spark_context = SparkContext('example','example')
streaming_context = StreamingContext(spark_context, 1) # 伪实时,每1秒计算一次目录增量
file_stream = streaming_context.textFileStream('/example')
streaming_context.checkpoint('/example')
………………
streaming_context.start()
if streaming_context.awaitTerminationOrTimeout(get_reset_seconds()) == False:
streaming_context.stop()
大功告成,这个任务会在每次 awaitTerminationOrTimeout 方法返回 False 的时候进入下一个循环,即每天0点的时候自动重启,清空原来的计算数值(state),完美的实现了需求。