一直以来公司都有个痛点亟待解决。分库分表的MongoDB上传数据至ODPS,于是就有了一套利用tunnel java sdk上传数据的服务。但是上传完数据后DataWorks上的任务链依赖如何开始传递,一直没有解决。
老办法是打时间差,按照一般上传耗时3个小时计算,所有任务的起点都配置在凌晨4点开始,这在大多数时候都能生效,但在一些流量特别大的日子就会异常,数据没传完,但任务已经开始执行了,导致执行的结果都是错的。
所以,需要有个任务能够嗅探数据已经传输完毕,后续的任务都依赖这个嗅探任务。
首先,新增一张表用作监控。
CREATE TABLE `one_day_monitor` (
`flag` BIGINT
)
PARTITIONED BY (
pt STRING COMMENT 'yyyymmdd'
)
LIFECYCLE 37000;
在正常传输完整数据后,在这张监控表里写一条记录,令当天分区的flag = 1
。之后的操作就围绕这个1
来进行。
终于来到标题内容,创建一个PyODPS节点,过程不赘述了。
先贴代码:
import time
t = o.get_table('one_day_monitor',project='xxxxx')
pptt = 'pt={}'.format(args['bizdate'])
end_flag = 1 ##结束标记
th = 1 ##时间标记,小时维度
while end_flag and th < 8:
reader = t.open_reader(partition=pptt)
f = reader[0].flag
if f == 1:
end_flag = 0
else:
time.sleep(600)
lt = time.localtime(time.time())
th = lt.tm_hour
if th >= 8: ##如果运行到8点则直接终止该任务
exit('超时结束')
else:
print '正常结束'
简单解释下,
args['bizdate']
是PyODPS的参数调用方式,详情可见我上一篇博文或阿里云官方文档;end_flag
标记取到监控表的flag
是否为1,用于退出循环;time
模块取到当前的小时数,如果超过8点则退出,并在后续的条件判断力报错,用于任务失败;本以为结束了,测试通过——安心提交——打包发布,等待明天的任务调度。
一早来看,竟然失败了,遂查看任务运行日志,发现任务开始执行时,one_day_monitor
表没有当日分区,当日分区是SDK数据上传时创建的,任务开始执行时找不到该分区导致报错。测试时是下午,当时分区数据已经存在,所以没有发现这个bug,于是调整思路微调下脚本。
既然取记录时分区有可能还未创建,那么只要分区创建了不就代表数据已经传输完成么。于是从判断字段flag
是否为1,转变为判断是否存在分区即可,代码见下:
import time
t = o.get_table('yp_one_day_monitor',project='devops')
pptt = 'pt={}'.format(args['bizdate'])
end_flag = 1
th = 1
while end_flag and th < 8:
if t.exist_partition(pptt): ##判断是否存在分区
end_flag = 0
print '取到分区啦'
else:
time.sleep(600)
lt = time.localtime(time.time())
th = lt.tm_hour
if th >= 8: ##如果运行到8点则直接终止该任务
exit('超时退出!')
else:
print '正常结束'
虽然Python老早就会写,但是在ODPS上使用Pyhton来解决问题还是第一次。使用这种高级语言可以完成很多单纯SQL没法完成的骚操作,接下来也会继续深入体验阿里云的PyODPS。
如果读者有跟我相似的工作上的困扰,除了搬运文中代码外,SHELL节点理应也能完成类似的功能,敬请自行体验啦。
后来又发现了新的问题,采用自定义参数args['bizdate']
时,节点点击运行(F8)
运行正常,但是在运维中心的调度实例均报错,参数没有被正确调用。
改为系统参数的调用方式后,结果相反,在节点的运行异常,但是周期实例、测试实例、补数据实例均能正确执行。
这。。。我目测应该是阿里云的BUG,如果有读者知道详情的,诚挚请教。