总 第22篇
2020年 第01篇
导读
Azkaban是LinkedIn公司于2012年开源的“工作流调度”引擎, 与之类似的有「Oozie」, 「Airflow」,「DolphinScheduler」等工作流调度系统。
自2014年起,一点资讯使用Azkaban搭建核心大数据生产系统,支持Hive任务、SparkSQL任务、Spark任务、Python任务等多类型数据生产任务的执行。
本文总结了过去6年里,团队对Azkaban系统的使用、运维经验,介绍了一点资讯在用户侧和管理侧对Azkaban的改造优化工作和运维实践:
一、使用情况
系统在双机房4个集群进行部署,日均调度总量34000+,总部署任务流1500+,全年服务可用性99.95%
1.1 一点资讯Azkaban使用情况总结
在用户使用和运维过程中,我们发现存在「缺失跨工程调度依赖」、「调度机单点」、「监控缺失与运维工具匮乏」、「内存资源泄露」和「执行机升级周期漫长」等一系列共10点问题:
图1.2 Azkaban问题总结
针对上述问题,我们通过修改源码的方式增强并完善了Azkaban系统,优化项目为:
用户侧功能增强优化6项:跨工作流调度支持、数据血缘计算与可视化、多通道报警系统、作业运行日志检索、Hybrid账户管理体系、多类型触发器
管理侧运维效能提升5项:Web调度容器化与HA改造、执行机(executor)平滑升级、资源清理与回收系统、丰富的运维工具、监控体系完善
二、用户侧易用性升级:
2.1 跨工作流调度支持:
已有问题:开源版本Azkaban仅支持同一个Project下不同Job间的直接依赖(以此形成Flow)。
在实际生产中,业务方经常提出需要跨Project进行依赖检查(目的是方便管理和实现一对多触发)
解决方案:一点资讯通过Hive表构建Flow与Flow之间的依赖检查。具备天级别分区数、小时级别分区数、分区名称过滤的多类型依赖检查能力。工作流按时间点触发后,先检查上游依赖输出的Hive表是否存在,就存在并满足要求则触发后续的计算任务。
使用技术:Hive分区管理、Azkaban依赖检查(自研)
图2.1 跨工作流依赖
2.2 数据血缘关系计算与可视化:
已有问题:Azkaban是一个进程调度系统,每一个大数据任务和普通的进程任务没有区别,尤其是无法知晓Spark任务产出的Hive表和HDFS直接的关系。
解决方案:一点资讯通过添加Hive钩子函数,记录Add分区时的JobID+FlowID,同时结合每个Flow触发时的分区输入,通过Flink计算血缘关系,并在“一点大数据开发平台-Shark”中展示。
使用技术:Hive钩子函数+ELK日志收集+Flink分析+分区依赖检测系统
图2.2 数据血缘关系计算与可视化
2.3 多通道报警系统:
已有问题:开源版本只有邮件报警,缺乏通用的短信报警和电话报警支持。
解决方案:修改UI,支持短信报警+电话报警+邮件报警的支持,并且当用户创建调度任务时,自动补全当前用户报警邮箱,并自动创建12小时的SLA到调度里;
目前Azkaban还是用的BootStrap库和Velocity等旧UI框架,技术稍显老旧,难于利用新的node.js 框架和技术进行扩展。(例如,现在的dubbo-admin-ui等后台项目均已经迁移到Node.JS体系中)
使用技术:Velocity、BootStrap
图2.3 智能报警系统(Email+SMS+Telphone)
2.4 作业运行日志检索:
已有问题:原生开源版本需要通过WebServer获取执行日志状态,每次需要WebServer连接executorServer进行获取。当重量级作业或长时间运行作业需要查看日志时非常痛苦。举例:默认配置下,每次取日志的大小为50KB当日志量达到20MB时需要拉取400次。
解决方案:一点资讯通过日志收集系统,收集每台执行机的执行目录/executiron/*.log 文件,以FileBeats发送到Kafka中进行处理,由LogStash写入ES集群,最后用户借助Kibana和自研Lark平台完成日志的二次分析。
使用技术:SpringBoot+Vue.js+FileBeats+ES+Kafka
图2.4 作业日志检索统一化
2.5 Hybrid账户管理体系:
已有问题:当使用简单登录方式时,可以访问所有项目,且无法限制, 当使用LDAP验证时,又需要频繁配置代理账号(ProxyUser),使用很不方便。
解决方案:通过自定义登录插件,在原有用户名和密码的基础上,增加LDAP检查,设置不同用户登录不同的代理用户,新人入职后可以自助申请登录权限,实现代理账户和LADP账户的动态多对多管理,下图展示了一点Azkaban账号管理平台:
使用技术:Vue.js + Vue-ant-design+SpringBoot框架开发
图2.5 Hybrid账户管理体系
2.6 多类型触发器:
已有问题:开源版本3.0.0版本仅支持时间触发,从3.42.0开始支持Kafka触发方式
解决方案:一点资讯通过扩展WebServer的调度方式,支持5种触发机制(后3种自研):
触发方式 | 使用场景 | 使用方式 | |
1 | 定时触发 | 日常数据生产作业 | 同社区版本 |
2 | Event触发 | Kafka事件触发Azkaban数据计算 | 同社区版本,通过指定Kafka事件触发调度(仅测试环境部署) |
3 | 定时触发+依赖检查 | 日常数据生产作 | 时间触发,增加基于Hive的数据依赖检查 |
4 | 回溯历史触发 | 数据仓库工程师回溯数据 | 通过配置「开始时间」、「结束时间」、「时间间隔」来生成对应的作业列表,并且可以配置并行度来进行历史数据恢复 |
5 | 外部API触发 | 外部脚本触发、调度空洞回填等 | 针对算法等高度定制化需求,采用WebAPI Hook来触发 |
三、管理侧运维效能提升:
Azkaban用户侧问题优化后,在系统运维阶段依然有「调度机单点」、「执行机升级周期长」、「资源泄露」、「缺乏监控」等一系列增加系统风险的问题,下面介绍一点资讯在运维侧的优化升级经验:
3.1 Web调度容器化与HA改造:
已有问题:调度机单点,WebServer和调度服务耦合在一起
在原始Azkaban中,WebServer和调度服务耦合在一起,在Azkaban3.0阶段社区一直没有HA版本的WebServer计划(4.0阶段已有相关Plan)
1:若调度节点假死,将导致调度任务无法下发,引起调度空洞产生。
2:升级Web是高频场景,升级调度是低频场景,两者耦合导致升级风险增加。
解决方案:
第一阶段:完成WebServer(调度节点)的容器化改造,并部署在Marathon或k8s上。配置Health检查和保证调度进程的HA(通过容器调度平台保证HA);
第二阶段,我们通过升级第一阶段的DeploySet,通过伴生容器中的FileBeates不间断收集WebServer调度日志,使用Flinlk监控系统运行状态并计入OpenTSDB。目前支持的监控项目有:调度频率、执行机Slot数、CPU、Mem等关键指标,并通过一点自研报警平台实现异常数据的上报与报警。
关键技术:Docker、Marathon、Kubernetes、Filebeats、Flink、TSDB、Grafana
图3.1 Web调度容器在Marathon和k8s上部署
3.2 执行机(executor)平滑升级:
已有问题:开源方案中,若直接升级Executor,则标记任务为失败状态,并发送大量报警短信
问题原因:原因是Azkaban会每隔一定时间Ping Executor,获取执行机的CPU、Mem等信息,若Ping失败,则标记该执行机上的作业为Failed。
场景1:执行机在检查窗口(1分钟内)快速恢复,由于执行机内存中已经没有工作流,则当下次WebServer发起进度检查指令时,执行机回复Unknown错误,调度机标记作业为Failed状态。
场景2:执行机没有在检查窗口中恢复。WebServer标记该执行机上所有任务为Failed状态。
值得注意的是,尽管WebServer标记为失败状态(UI显示失败)但却不是完全失败,这是因为已经运行中的Job进程并没有被Kill(而是被Init进程托管)后续需要运行Job进程的确不会再被提交。最终状态是形成了——既没有执行成功、也没有完全失败的尴尬局面。
图3.2.1 直接重启导致Job失败
社区方案:先临时下线任务(标记Executor为失效状态)等待所有任务执行完毕,再重新启动Executor,由于大数据很多作业需要几个小时的时间才能结束,因此整个升级过程及其漫长,且会加重其他节点的压力(任务分流至其他节点)
解决方案:一点资讯修改调度机和执行机的代码,实现平滑升级。
在调度机端:当Ping执行机失败时,暂时标记任务为Unknown状态,等待执行机拉起,并设置1H的超时时间。
在执行机端:当执行机重启后,若收到调度机询问状态的Ping请求,则先检查工作目录中是否有相关任务,若有则证明是重启状态,从DB中恢复相关Flow,在内存中重建,标记所有Job为Start状态,重算整个工作流。
收益: Azkaban执行机的平滑升级,大大加速了执行机的升级过程(升级过程从十几个小时变为几分钟)
关键技术:Azkaban WebServer平滑升级模块(自研),Executor平滑升级模块(自研)
图3.2.2 一点执行机平滑升级方案
3.3 资源清理与回收系统:
已有问题:作业相互影响,内存泄露。Azkaban作业结束但是进程退出不完全。例子1:Python进程Kill后,子进程不退出,一直占用内存,需要扫描所有的僵尸进程。例子2:Spark等程序启动后,由于用户代码问题,导致任务超时被KIll,但是子进程不退出最后导致Spark Driver端内存泄露。
解决方案:
1:内存级联Kill。从发送Kill -9 到第一个进程,改为遍历进程树,逐一发送Kill命令
2:内存泄露巡检系统。在每个执行机上执行机上运行巡检系统,遍历Linux 进程,若进程工作目录属于 /log/executions/exec_xxx 并且对应的Execution已经结束,则发送进程Kill命令,完成内存清理。
3:设立内存巡检任务(crontab)定期扫描内存大于阈值的进程,如果用户作业内存超过阈值,则自动发送级联Kill命令。
通过以上方式,内存使用率从83%降至40%,利用率提升近1倍。
3.4 丰富的运维工具:
已有问题:运维工具缺乏,开源版本只有用户平台,缺乏管理工具和故障恢复工具。
解决方案:
空洞检查工具:基于调度的频率和调度任务列表,计算实际发生的调度和存在调度直接的Gap。
运维空洞补齐工具:当空洞发生时,根据已有的作业ID,结合历史调度信息,克隆工作流,修改工作流基准时间重新提交。
用户账号管理工具:采用一级、二级管理员机制,授权二级管理员添加所属组的成员,实现更好的账号管理。
3.5 监控体系完善:
已有问题:目前社区版本几乎没有监控手段,仅能通过UI获取正在执行的作业状态。
解决方案:
1:通过Flink分析日志,实现执行机槽位、执行机负载、执行机内存、执行机端口可用性监控
2:自我监控状态上报(每分钟执行自检调度作业,自动作业失败则触发报警)
3:调度机端口监控、日志监控、错误日志监控报警
图3.3 监控体系完善(Hive+自检任务上报+Slot检查+CPU+内存+调度频率)
四、后续发展规划:
通过第二、第三部分的介绍,我们系统归纳了过去6年一点资讯对Azkaban的改造优化工作,但Azkaban仍然有很多先天性缺陷导致后续扩展升级困难。
为彻底解决使用和扩展中遇到的难题,一点资讯针对业务需求,自主研发了新的离线作业生产调度平台:
1:针对专业调度任务,通过自研的「数据应用调度系统」,支持Presto->MySQL, SparkSQL->MySQL, Hive->Hive, Hive->MySQL, Hive->Email, MySQL->Email等常用的数据ETL逻辑,后续会进一步扩展常用的数据加工算子,实现拖拽式定制化数据加工。
2:针对通用调度任务,我们正在研发容器化分布式调度系统,彻底解决调度节点单点缺陷, 调度作业互相干扰, 作业失败问题排查困难等缺陷,并提供丰富的离线+实时调度能力、依赖检查能力以及精细化数据血缘建设功能。相关工作将在后续陆续分享,敬请关注团队公众号↓↓↓↓↓
长按二维码,关注公众号