注:【本文正在参与“拥开源 — Apache DolphinScheduler 有奖征稿活动”】
项目背景
Apache DolphinScheduler是一个分布式去中心化,易扩展的可视化DAG工作流任务调度系统。致力于解决数据处理流程中错综复杂的依赖关系,使调度系统在数据处理流程中开箱即用。
我司数据中台项目中基于1.2.0版本集成并二次开发了DolphinScheduler调度,将DolphinScheduler调度作为数据中台服务的核心能力之一。使用方式是ds单独部署,数据中台服务通过ds的client包进行调度功能集成。
事故回顾
端午节刚刚过完上班第一天,早早到了公司,发现钉钉已经好几个艾特自己的信息了,说是客户现场调度模块的流程实例列表无法正常显示,需要帮忙排查并解决。
因为调度集成在数据中台项目中,所以并不一定是调度模块出了问题,简单看了一下调度的其他接口,正常服务。遂通知数据中台的同学查看是否上层应用报错。数据中台上层同学排查后返现调度返回正常,上层应用存在NPE。究其原因,问题出现在流程实例状态枚举字段上,上层应用未使用调度client包给出的流程实例状态枚举类,手写的流程实例状态枚举与调度自身枚举字段不一致(WAITTING|WAITING)。相信很多熟知的调度的同学都知道,ds等待中状态的这个英文单词有误,上层应用修正了,导致枚举状态不一致NPE。
统一一下就解决了啊!
于是统一了一下使用WAITING,流程实例列表正常显示!
客户马上再次发来求助,新的所有手动运行的调度流程都卡在等待状态了,没办法正常执行任务!
事故分析
- 机器资源不足导致流程实例等待了?
简单看一下机器资源,调度使用的机器资源cpu百分之十几,内存百分之三十几,机器平均负载也很低,看起来没啥问题啊! - 运行中任务太多线程满载导致流程没有线程资源了?
调度是集群部署的,work机4台,每台work线程配置是500,满载时理论上可以支持2000个任务同时运行,而且运行一结束就会马上释放资源,给到其他的任务,客户那边一般运行的任务除了高峰时期,也没有这么多的啊!
查看调度master日志,正常执行,没有问题。
查看work日志,也在运行,看起来没有啥毛病。不过细心观察后发现,work日志时不时的打印thread insufficient , activeCount : 500, workerExecNums : 500, will sleep : {} millis for thread resource
。这个时候问题就很明显了啊,单台work节点运行中work数量超过500了。
那么问题就清晰了,确实是工作线程满载引起的。告知客户调度在运行,不过运行任务太多,其实并没有卡死;客户马上不满意了,我紧急需要执行的任务执行不了了,机器资源充足,你得给我解决啊!
事故处理
等待中状态存在的主要原因要么是机器资源不足,要么是工作线程满载,那么现在知道是线程资源不足,简单处理,当然是加大线程资源,让其他任务跑起来了。简单处理能保证接下来任务数量太多不出现同样问题吗?不能!
于是过滤运行中任务,发现运行中任务真的2000多个(超过2000个是因为部分任务虽然是运行中,但是没有持有线程资源)。简单看一下运行的任务,是每5分钟调度的任务居多,我们简称微批任务,是不是5分钟根本运行不完这个任务导致的任务堆积?
简单看一下任务详情,while循环写的挺6的,一看日志,这是个死循环!!!这才是问题的根源。
征求客户同意后把这个流程停止调度了,把运行中的微批任务全部停止。
激动的场景:等待中流程瞬间少了一堆,等待的流程任务开始涌入!
事故总结
- 工作线程硬编码,不能弹性扩容,可以优化!;
- 告警机制不完善,如果这部分有提前告警,不会给用户错觉:卡死了!;
- 任务执行时间预判规则,如果任务执行时间超过预判时间,则进行预设规则处理,kill或者告警给用户,也能够大概率避免这种情况。
结语
DolphinScheduler开源发展的飞快,在大数据调度这块越来越完善。遇到的这个问题到时候也会在ds双周会上和其他小伙伴交流一下。集众薪,燃盛炬,希望DolphinScheduler越做越强大,为技术领域带来更多的发展与便利!