调度系统批量重跑任务的思考

在调度系统中总会遇到这种场景,上游任务出现数据问题,数据缺失,数据重复。这些问题出现的原因有很多,比如上游业务问题,升级某一调度组件测试覆盖不全面,代码bug等。 出现问题的原因,问题的修复,系统针对问题的升级改造,其实这一整套的链路很复杂的逻辑。

本文从几个方面对这类问题进行一些思考;

问题发现

在DQC规则报警没有全面覆盖的场景下,数据问题的发现大部分场景都是依靠业务方对业务的感知,或者线上用户的投诉的反馈。对于kpi任务而言,如果在上游任务执行初期监测的到,就可以立即停止链路调用,去梳理其他业务是否有同样的问题,但是在大部分场景下,问题的出现都是在下游数据已经反馈给线上用户的时候,开发同学才会知晓,在这种时候就比较被动了。
我们不可能指望通过线上反馈来发现问题,所以很大程度上,我们需要依赖数据质量来提供保障,但是对于大部分小公司而言,数据的快速产出,以及低成本开发可以更重要一点,在这种情况下,开发同学只能自求多福了。

比如:数仓同学接到业务反馈数据出现问题,但是这种问题是个案还是整体,是否还有其他业务出现类似问题,在这种情况下,平台侧同学应该怎么做,才能降低误判,或者真正出现问题,把业务影响降到最低。

  1. 在问题没有搞清楚之前,是否需要停止output任务(数据到业务侧的任务)的调度?我觉得是有必要的。宁愿损失一点时间,也要保证线上业务的正确。
  2. 问题的排查,无非是离线/实时任务校对,或者根据经验去查找链路。在这种情况下如果出现差异很大的情况下就可以假定离线任务出现问题。在这种情况下,就要确保正在运行的任务全部暂停或者kill掉。全面检查链路。
  3. 问题是个案?还是其他任务也有类似问题。这个很难判断,比较机智的做法就是,所以业务线的同学拉群check,check核心链路的数据的。然后对问题原因查找,以及紧急修复。
  4. 一般而言,如果问题的原因是个案,一般都是代码问题,或者上游数据有问题,如果是多个任务都有相似问题,这个就要对问题原因进行仔细排查,找到原因,避免造成重跑数据后数据依然是错误的局面。

总之发现问题,应该及时暂停output任务,以及对于已经流出的数据,能回退就回退,不能回退,赶紧和业务方进行解释,避免造成更多的损失。
对问题进行仔细排查,并且做重跑任务的准备。宁可晚点调度重跑任务,进行整体链路进行检测,也不要放过一个可能数据出问题的地方。因为后者会造成更多时间的浪费。
如果出现问题的原因是多个任务都有类似问题,要根据链路逐一排查,不放过任何一个出错的地方,因为任何一个上游任务出错,下游都是一大片数据报错,都是致命性的。

理论只是理论,问题的发现是一个团队协作的过程,而且过程中就不要怕背锅,既然问题已经产生,把损失降到最低才是最优解。

数据重跑

在问题排查出来之后,就需要对任务进行重跑。

  • 如果是系统问题,要在重跑之前进行修复,并且check。一般而言,系统问题都是最近做了升级或者改动导致的,回退即可。回退不了的,打补丁修复。
  • 如果是业务问题,比如业务的代码出现问题,而且是大量的,就要先筛选出来所有问题的最上游,根据最上游的任务进行重跑。

重跑的逻辑有两种一种是针对某几个链路的根节点生成重跑的子节点和对应的依赖关系。但是这种方案有几个问题:

  1. 需要对某几个链路的所有节点重新生成,如果节点达到w级别,生成出错的概率很大,而且会出现卡顿的情况。
  2. 正常调度暂停和未执行的执行计划和调度实例,会和重跑的任务形成并行的关系。如果正常调度的没有暂停,或者kill掉。即使我们在调度系统做了幂等和串行的操作。也避免比了两个相同的重跑实例在某些临界点,比如(同时请求,前后执行脚本有删除表结构,重新生成的逻辑。)造成的数据出错问题。
  3. 在平台侧开始重跑任务的时候,如果业务方因为排查不仔细,又发现新的链路出现问题,而这个链路和当前重跑的链路有交集?新的重跑势必产生2的问题。
  4. 在重跑之前对正常调度的任务进行暂停或者kill。平台侧的同学要在所有重跑任务完成之后,手动把这些暂停和kill的任务以及下游置为成功,或者正常调度。否则会出现第二天任务上游依赖未完成的问题。

第二种方案是:删除原来有关联的链路的所有下游,然后出发最上游的节点,让系统自动重新调度。
这种方案就避免了前者的并发问题和第二天的依赖问题。如果还有其他链路出错,可以继续采用这种方案删除相关链路和子节点,重新生成。当然这些生成出来的是执行计划而已。所有的依赖关系还是需要重新在依赖满足的情况下触发生成。

所以:数据重跑有两种方案,对于小批量的数据重跑,以及历史数据的重跑可以直接生成重跑实例即可。对于大批量的任务重跑,尤其是当天kpi任务故障的情况,建议还是采用第二种方案。

重跑的过程中要确定的问题:
1:哪些任务是可以通过重跑得到结果。
2:哪些任务是必须要手工去修复(比如某些非幂等的任务)。最好的办法就是在调度系统侧能标注好哪些任务是非幂等的。这样业务方也能以最快的时间来修复。

资源调配

大批量任务重跑的时候,和正常调度的资源需求是不一样的,正常调度的时候,在对应的时间点,只需要进行必要的削峰,限制对应任务的并行度即可。但是在大批量任务重跑,而且需要尽快产出数据的时候,就需要特殊处理。

  1. 集群该扩容的扩容,该弹性的就多弹点,毕竟数据产出才是第一位。
  2. 调度侧应该限制其他非核心调度任务的并发度,把重跑任务的优先级调整到最高,但是小时任务,时间调度的任务可以保持不变。非相关链路的任务给予并发度的限制,但是不能影响链路的产出。
  3. 重跑任务的并发度可以根据集群的容量做一定的限制。kpi重跑任务优先调度,然后才是普通重跑任务的调度。

需要做几套并发度调整的预案,在大批量任务重跑,大促等都可以一键进行切换,避免手忙脚乱。
针对并发度限制无法满足所有情况的时候,可以手工的去调起在池子中的调度实例,避免业务方的催促。
资源调度的关键在于,把资源绝大多数让给重跑任务,尤其是kpi任务。并且可以针对类似问题,做一套标准的流程模板。后续出现问题,直接对应模板做操作即可。

数据质量

在调度系统大批量出现问题的后续,我们很自然的会想到数据质量的重要性,如何能配置好的DQC报警,在数据传给下游之前能尽可能的验证数据的准确性,但是想要做好数据质量却是比较难,
1:数据质量需要消耗大量的计算和时间,比如kpi是7点正常产出,如果加上DQC报警,可能需要9点或者更晚。
2:数据质量和调度系统是应该解耦,还是应该耦合在一起。如果是解耦关系,任务的下游可能会有10+的DQC任务,并且需要额外条件和下游关联的节点。并且下游执行需要判断哪些上游是非必须执行成功的。如果是耦合的,上游任务执行完成之后,如何并行的调用下游的dqc并且触发下游任务?所以大概率还是会采用前者,使用解耦的关系,下游配置一个虚拟节点,去和下游任务进行关联。
3:数据质量的范围包括了各种限制条件,简单的就是表非空,表数据量同环比浮动。字段的唯一性,非空,枚举,范围等约束。更复杂的还要针对某些业务场景下比如uv的浮动等。离线和实时任务校对。

当然,上面说的只是一些实操,但是更核心的要保证端到端的数据一致性保证,比如mysql-binlog 同步到hive,尤其是在涉及到分库分表,有upsert操作情况下,如何能保证端到端数据传输的一致性,以及数据质量该怎么做?对于类似场景的数据同步不可能一步到位的通过数据交换组件一次性同步,往往会加一层中间层数据库,把数据先写入中间层数据库,然后再统一的通过数据交换导入到hive。如何能保证数据的准确行,以及在哪个环节去做DQC.其实都是一个值得深思的问题。
以这个例子来说,端到端的数据质量,有两个需要考虑的点,
1:如何获取分库分表数据库表的数据量和中间层的数据库做比较。

2:如何验证数据的状态一致,比如对于upsert操作,怎么保证数据不出现乱序等因素,保证数据状态和数据库库一致。

针对1,首先需要保证分库分表有分区的字段,如果能进行分布统计再合并,就再好不过了,不过对于求复杂sql的能力其实还是不能保证的,只能寄希望于中间件的能力。或者从binlog中拿到所有insert操作的记录数,和目标数据源对比。也是一种手段。
针对2, 在处理binlog的时候,不可能做到中间件全局有序,只能做到分区有序,并且分区插入的目标数据库的时候,还要做好容错。

总之端到端的数据质量的难度,比其他环节的更加麻烦,验证也更加困难,如果只是少量数据缺失或者有问题,只能寄希望于人工修复。大量的数据问题,也只能做到数据量的保证。其他的能做的比较有限。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值