奇富科技(原360数科)是人工智能驱动的信贷科技服务平台,致力于凭借智能服务、AI钻研及利用、平安科技,赋能金融机构提质增效,助推普惠金融高质量倒退,让更多人享受到平安便捷的金融科技服务。作为国内当先的信贷科技服务品牌,累计注册用户数2亿多。

奇富科技之前应用的是自研的任务调度框架,基于Python研发的,常常面临着调度不稳固的情况,难以保护。起初引入了Apache DolphinScheduler作为公司的大数据任务调度零碎,面对大量任务调度的考验,经验了半年磨合期,目前Apache DolphinScheduler在奇富科技运行十分稳固。本文将介绍该公司团队最近一年在开源版Apache DolphinScheduler根底上所做的优化和改良。

一、技术架构

在咱们公司的大数据离线任务调度架构中,调度平台处于中间层。用户通过数据集成平台提交数据同步工作给调度平台,通过数据开发平台提交工作流给调度平台。用户不和调度平台间接交互,而是和数据集成平台和数据开发平台交互(图1)。

因为咱们是一个金融相干业务的公司,业务须要保障高可用。因而,咱们的调度平台是异地双机房架构,外围工作流会异地双机房运行。集群角色分为cluster A和cluster B,其中cluster A为主集群,cluster B为从集群(图2)。用户的工作流在A集群运行,其中外围要害工作流会在A和B集群双机房运行。以下是调度集群各服务个数。其中Api、Alter、Master服务在虚拟机部署,Worker和Logger部署在物理机上。


二、业务挑战

01 调度任务量大

咱们目前每天调度的工作流实例在3万多,工作实例在14万多。每天调度的任务量十分宏大,要保障这么多任务实例稳固、无提早运行,是一个十分大的挑战2

02 运维简单

因为每天调度的工作实例十分多,咱们经验了几次调度机器扩容阶段。目前2个调度集群有6台Master、34台Worker机器。而且调度机器处于异地2个城市,减少了很多治理运维复杂性。

03 SLA要求高

因为咱们业务的金融属性,如果调度服务稳定性出问题,导致工作反复调度、漏调度或者异样,损失会十分大。

三、调度优化实际

咱们在过来一年,对于调度服务稳固,咱们做了如下2个方向的优化。第一,调度服务稳定性优化。第二、调度服务监控。

01 反复调度

在2023年初,用户大规模迁徙工作流时,遇到了工作流反复调度问题。该问题,景象是同一个工作流会在同一个集群同一时间,生成2个工作流实例。通过排查,是因为用户在迁徙时,会有工作流迁徙我的项目的需要,比方从A我的项目迁徙到B我的项目。在工作流上线时,用户通过提交工单,批改了调度数据库中工作流的我的项目ID,进行迁徙。这么做会导致该工作流所对应的quartz元数据产生2条数据,进而导致该工作流反复调度。如图3所示,JOB_NAME为’job_1270’的记录,有2条数据,而JOB_GROUP不一样。查问源码job_name对应工作流的定时器ID,JOB_GROUP对应我的项目ID。因而批改工作流对应的我的项目ID,会导致quartz数据反复和反复调度。正确迁徙工作流我的项目的形式是,先下线工作流,而后再批改我的项目ID。


如何防止和监控此问题,咱们依据这个逻辑,写了反复调度的监控sql,在最近一年中,数次提前发现了quartz的漏调度问题。

SELECT count(1)FROM     (SELECT TRIGGER_NAME,        count(1) AS num    FROM QRTZ_TRIGGERS    GROUP BY  TRIGGER_NAME    HAVING num > 1 )t

02 漏调度

在2023年初,在凌晨2点,有些工作流产生漏调度,咱们排查后发现是凌晨2点0分调度太集中,调度不过去。因而咱们优化了quartz参数,将org.quartz.jobStore.misfireThreshold从60000调整为600000。

如何监控和防止此问题,监控sql摘要如下:

select TRIGGER_NAME,NEXT_FIRE_TIME ,PREV_FIRE_TIME,NEXT_FIRE_TIME-PREV_FIRE_TIMEfrom QRTZ_TRIGGERSwhere  NEXT_FIRE_TIME-PREV_FIRE_TIME=86400000*2

原理就是依据quartz的元数据表QRTZ_TRIGGERS的上一次调度工夫PREV_FIRE_TIME和下一次调度工夫NEXT_FIRE_TIME的差值进行监控。如果差值为24小时就失常,如果差值为48小时,就阐明呈现了漏调度。

如果曾经产生了漏调度如何紧急解决? 咱们实现了漏调度补数逻辑通过自定义工作流进行http接口调用。如果监控到产生了漏调度状况,能够立刻运行此工作流,就能把漏调度的工作流立刻调度运行起来。

03 Worker服务卡死

这个景象是凌晨调度Worker所在机器内存占用飙升至90%多,服务卡死。

咱们思考产生该问题的起因是,调度worker判断本机残余内存时,有破绽。比方咱们设置worker服务残余内存为25G时,不进行任务调度。然而,当worker本机残余内存为26G时,服务判断本机残余内存未达到限度条件,那么开始从zk队列中抓取工作,每次抓取10个。而每个spark的driver占用2G内存,那么本地抓取的10个工作在将来的内存占用为20G。咱们能够简略计算得出本机残余内存为26G-20G为6G,也就是说抓取了10个工作,将来的残余内存可能为6G,会面临严重不足。

为了解决这个问题,咱们参考Yarn,提出了”预申请”机制。预申请的机制是,判断本机残余内存时,会减去抓取工作的内存,而不是简略判断本机残余内存。

如何获取将要抓取工作的内存数呢? 有2种形式,第一种是在创立工作流时指定本工作driver占用的内存,第二种是给一个固定平均值。

咱们综合思考,采纳了第二种形式,因为对于用户来说,是没有感知的。咱们对要抓取的每个工作配置1.5G(经验值)内存,以及达到1.5G内存所须要的工夫为180秒,抓取工作后,会放入缓存中,缓存过期工夫为180(经验值)秒。残余内存计算公式,本机残余内存=本机实在物理残余内存-缓存中工作个数1.5G+本次筹备抓取的工作数1.5G 。

还是同样的场景,本机配置的残余内存为25G,本机理论残余内存为26G,要抓取的工作为10个。每个工作将来占用的driver内存为1.5G。简略计算一下,本机残余内存=26G-10*1.5G。在“预申请”机制下,本机残余内存为1G,小于25G,不会抓取,也就不会导致Worker机器的内存占用过高。那么会不会导致Worker服务内存使用率过低呢,比方shell、python、DataX等占用内存低的工作。论断是不会,因为咱们有180秒过期机制,过期后,计算失去的本机残余内存为变高。

依据同样的原理,CPU占用,咱们也加上了同样的机制,给每个要抓取的任务分配肯定的cpu负载值。

加上内存预申请后,最近半年,没有遇到因为内存占用过高导致worker服务卡死的问题。以下是咱们加上内存预申请机制后,worker内存使用率状况,能够看见worker最大内存使用率始终稳固放弃在80%以下。

04 工作反复运行

在worker服务卡死时,咱们发现yarn上的工作没有被杀死,而master容错时导致工作被反复提交到yarn上,最终导致用户的数据异样。

咱们剖析后发现,工作实例有一个app_link字段,寄存用户提交的yarn工作的app id,而第一次调度的工作的app id为空。排查代码发现worker在运行工作时,只有实现的yarn 工作,才会更新app_link字段。这样导致master在容错时,拿不到app id,导致旧工作没有被杀死,最终导致工作反复提交。

咱们进行的第一个改良点为,在worker运行yarn工作时,从log中实时过滤出app id,而后每隔5秒将app id更新到app_link字段中。 这样yarn工作在运行时,也就能获取到app id,master容错时就能杀死旧工作。

第二个改良点为,在worker服务卡死从而他杀时,杀死本机上正在运行的调度服务,这样可能master就不须要进行容错了。

施行这个计划后,最近半年没有遇到反复调度的yarn工作了。

05 弱依赖


经营标签对于时效性要求很高,关系到广告投放成果。他们提出了一个需要,他们对于某些依赖工作流,不是强依赖的,如果该父工作流在约定的工夫没有实现,那么就不进行依赖。为了实现这个需要,咱们引入了弱依赖的机制。旧依赖模式,咱们定义为强依赖,如果该工作流在约定周期没有运行实现,那么永远不能依赖胜利。而弱依赖,会期待到某个工夫,如果还没有实现,那么也会胜利。

06 虚构节点

咱们调度集群是双机房运行的,因而有些外围工作流是运行在2个机房的。比方有些数仓ads相干工作流是输入hive数据到mysql表的,而mysql数据源来不及双数据源,只有一个mysql。因而主集群导入数据到mysql表,从集群就不应该导入数据到mysql表中。因而咱们实现了虚构节点的性能,实现的指标是,此节点在主集群实在运行,在从集群虚构运行。

07 工作的yarn队列动静切换

咱们的yarn队列是依据大业务线进行划分的,队列个数并不多。咱们对于用户的调度工作稳定性须要保障,而常常须要到的一个状况是,yarn的队列常常被补数工作占用过多,导致用户失常的调度工作提交不下来。

因而,咱们提出了工作的yarn队列动静切换计划。 原理就是当用户补数时,数据开发平台依据用户所属业务线,找到该用户所属的yarn队列名称,而后将该队列名称提交到全局变量中。调度worker在对该工作进行调度时,会判断该全局变量是否有值,如果有就进行替换。

通过该计划,咱们实现了调度工作在失常队列中运行,而补数工作进入补数的小队列中运行。从而保障了失常调度工作的时效性和稳定性。

08 实例分页查问接口优化

每天调度的工作实例有14万多,咱们保留了2个月数据,那么工作实例的记录数约为1000多万条。而DolphinScheduler查问工作流实例和工作实例有join关系,须要通过join查问project_id,在查问一些大的我的项目的工作实例时,耗时最大为几分钟甚至间接卡死。

咱们提出的解决方案是,通过字段冗余,在工作流实例和工作实例中存储project_id,将join分页查问改为单表分页查问。 优化后,大我的项目的工作实例分页查问p99耗时从几分钟升高到200ms。

09 Worker保护模式

在worker发版时,咱们不应该影响用户调度的工作。因而,咱们实现了worker的保护模式。当worker开启保护模式时,该worker不会再新抓取工作,而曾经抓取的工作持续运行,从而不影响用户的调度工作。过4小时后,判断该worker上工作运行实现,再对该worker进行jar包替换和重启服务。通过这种形式,咱们可能做到DolphinScheduler发版对用户的调度工作无影响,用户无感知。

10 worker和nodemanager混部

随着业务倒退,公司每天调度的工作流实例越来越多,worker服务常常内存不足,须要申请大内存的机器作为worker调度机。不过,面临着降本增效的压力,咱们思考DolphinScheduler的worker服务能不能和yarn的nodemanager进行混合部署,因为咱们的yarn集群有1000多台机器。咱们心愿通过这种形式达到不必申请新的机器,从而降低成本的指标。

咱们的解决方案如下,新扩容worker服务在nodemanager上,在早晨23点,通过yarn命令将该混部的nodemanager可用内存调低为1核4G,从而进行yarn将任务调度到该机器上,而后调用api接口,敞开该worker的保护模式,让该worker调度ds调配的工作。在早上10点,通过调用api接口,关上worker的保护模式,从而进行worker调度ds调配的工作,并通过yarn命令将nodemanager的内存和cpu复原为正常值,从而让yarn分配任务到该机器上。

通过这种计划,咱们实现了凌晨该机器给DolphinScheduler的worker应用,白天给yarn的nodemanager应用,从而达到降本增效的指标。 新扩容的worker,咱们都采纳了这种形式。

四、服务监控

一个稳固的零碎,除了代码上的优化,肯定离不开欠缺的监控。而DolphinScheduler服务在每天调度这么大量时,咱们作为开发和运维人员须要提前晓得调度零碎和工作健康状况。因而依据咱们的教训,咱们在DolphinScheduler服务的监控方向做了如下事件。

01 办法耗时监控

咱们通过byte-buddy、micrometer等,实现了自定义轻量级java agent框架。这个框架实现的指标是监控java办法的最大耗时、均匀耗时、qps、服务的jvm健康状况等。并把这些监控指标通过http裸露进去,而后通过prometheus抓取,最初通过grafana进行展现,并依据prometheus指标进行告警。以下是master拜访zk和quartz的最大耗时,均匀耗时,qps等。

以下是master服务的jvm监控指标

通过该java agent,咱们做到了api、master、worekr、zookeeper等服务办法耗时监控,屡次提前发现问题,防止将问题扩充到用户感知的情况。

02 任务调度链路监控

为了保障调度工作的稳定性,有必要对任务调度的生命周期进行监控。咱们晓得DolphinScheduler服务调度工作的全流程是先从quartz中产生command,而后从command到工作流实例,又从工作流实例再到工作实例。咱们就对这个工作链路进行生命周期监控。

1)监控quartz元数据

后面曾经讲了咱们通过监控quartz元数据,发现漏调度和反复调度问题。

2)监控command表积压状况

通过监控command表积压状况,从而监控master是否服务失常,以及master服务的性能是否可能满足需要。

3)监控工作实例

通过监控工作实例期待提交工夫,从而监控worker服务是否失常,以及worker服务的性能是否可能满足需要。
通过如上全生命周期监控,咱们屡次提前发现worker服务的性能问题,提前解决,胜利防止影响到用户调度服务。

03 日志监控

后面咱们通过java agent实现了办法耗时的监控,不过这还不够。因而,咱们还通过filebeat采集了3台api、6台master、34台worker的服务日志到咱们公司的日志核心,而后对日志进行异样突增告警。

五、用户收益

通过最近一年对DolphinScheduler代码的优化,咱们取得的最大收益是近半年没有因为调度服务导致用户的SLA受影响,并屡次在调度服务呈现问题时,提前解决,没有影响到用户工作的SLA达成率。

六、用户简介

图片

奇富科技(原360数科)是人工智能驱动的信贷科技服务平台,秉承“始于平安、 恒于科技”的初心,凭借智能服务、AI钻研及利用、平安科技,赋能金融机构提质增效,助推普惠金融高质量倒退,让更多人享受到平安便捷的金融科技服务,助力实现共同富裕。作为国内当先的信贷科技服务品牌,累计注册用户数2亿多。

作者介绍

  • 刘坤元

奇富科技数据平台部大数据开发工程师,19年入职奇富科技,目前负责大数据任务调度零碎开发和工作治理工作。

  • 王洁

奇富科技数据平台部大数据开发工程师,19年入职奇富科技,目前负责大数据任务调度零碎开发工作。

本文由 白鲸开源科技 提供公布反对!