任务调度背景
可观测性平台的亿级任务调度框架设计
任务调度框架在日志服务的大规模应用
通用调度
操作系统:从单机操作系统Linux来看,内核通过时间片的方式来控制进程在处理器上的执行时间,进程的优先级与时间片挂钩,简单来说,进程的在单CPU或者某个CPU的执行由调度器来掌握;K8s被称为分布式时代的操作系统,在Pod创建后,K8s的控制面调度器通过对节点进行打分排序,最终选出适合的Node来运行Pod。
大数据分析系统:从最早的MapReduce使用公平调度器支持作业的优先级和抢占,到SQL计算引擎Presto通过Coordinator的调度器将执行计划中的任务分配到适合的worker上来执行,Spark通过DAGScheduler拆分成Stage,TaskScheduler将Stage对应的TaskSet最终调度到适合的Worker上来执行。
任务调度框架:在数据处理中常见的ETL处理任务、定时任务,这些任务具有多模的特点:定时执行、持续运行、一次性执行等。在任务执行过程中需要考虑任务的编排和状态一致性问题。
任务调度
定时类任务
任务调度应用:一条日志的历险
cat nginx_access.log |awk '{print $7}'| sort|uniq -c| sort -rn| head -10 | more
select url, count(1) as cnt from log group by url order by cnt desc limit 10
除了日志,系统还有Trace数据、Metric数据,它们是可观测性系统的三大支柱。这个流程也适用于可观测性服务平台,接下来来看下一个典型的可观测服务平台的流程构成。
数据摄入:在可观测服务平台首先需要扩展数据来源,数据源可能包括各类日志、消息队列Kafka、存储OSS、云监控数据等,也可以包括各类数据库数据,通过丰富数据源的摄入,可以对系统有全方位的观测。
数据处理:在数据摄入到平台后,需要对数据进行清洗、加工,这个过程我们把他统称数据处理,数据加工可以理解为数据的各种变换和富华等,聚集加工支持对数据进行定时rolling up操作,比如每天计算过去一天汇总数据,提供信息密度更高的数据。
数据监测:可观测性数据本身反应了系统的运行状态,系统通过对每个组件暴露特定的指标来暴露组件的健康程度,可以通过智能巡检算法对异常的指标进行监控,比如QPS或者Latency的陡增或陡降,当出现异常时可以通过告警通知给相关运维人员,在指标的基础上可以做出各种运维或者运营的大盘,在每天定时发送大盘到群里也是一种场景的需求。
数据导出:可观测性数据的价值往往随着时间产生衰减,那么对于长时间的日志类数据出于留档的目的可以进行导出到其他平台。
业务复杂,任务类型多:数据摄入,仅数据摄入单个流程涉及数据源可能有几十上百个之多。
用户量大,任务数数量多:由于是云上业务,每个客户都有大量的任务创建需求。
SLA要求高:服务可用性要求高,后台服务是升级、迁移不能影响用户已有任务的运行。
多租户:云上业务客户相互直接不能有影响。
可观测平台任务调度设计目标
支持异构任务:告警、仪表盘订阅、数据加工、聚集加工每种任务的特点不一样,比如告警是定时类任务、数据加工是常驻类任务,仪表盘订阅预览是一次性任务。
海量任务调度:对于单个告警任务,假如每分钟执行一次,一天就会有1440次调度,这个数量乘以用户数再乘以任务数,将是海量的任务调度;我们需要达到的目标是任务数的增加不会对打爆机器的性能,特别是要做到水平扩缩容,任务数或者调度次数增加只需要线性增加机器即可。
高可用:作为云上业务,需要达到后台服务升级或者重启、甚至宕机对用户任务运行无影响的目的,在用户层面和后台服务层面都需要具有任务运行的监控能力。
简单高效的运维:对于后台服务需要提供可视化的运维大盘,可以直观的展示服务的问题;同时也要对服务进行告警配置,在服务升级、发布过程中可以尽量无人值守。
多租户:云上环境是天然有多租户场景,各个租户之间资源要做到严格隔离,相互之间不能有资源依赖、性能依赖。
可扩展性:面对客户的新增需求,未来需要支持更多的任务类型,比如已经有了MySQL、SqlServer的导入任务,在未来需要更多其他的数据库导入,这种情况下,我们需要做到不修改任务调度框架,只需要修改插件即可完成。
API化:除了以上的需求,我们还需要做到任务的API化管控,对于云上用户,很多海外客户是使用API、Terraform来对云上资源做管控,所以要做到任务管理的API化。
可观测平台任务调度框架总体概览
存储层:主要包括任务的元数据存储和任务运行时的状态和快照存储。任务的元数据主要包括任务类型,任务配置、任务调度信息,都存储在了关系型数据库;任务的运行状态、快照存储在了分布式文件系统中。
服务层:提供了任务调度的核心功能,主要包括任务调度和任务执行两部分,分别对应前面讲的任务编排和任务执行模块。任务调度主要针对三种任务类型进行调度,包括常驻任务、定时任务、按需任务。任务执行支持多种执行引擎,包括presto、restful接口、K8s引擎和内部自研的ETL 2.0系统。
业务层:业务层包括用户直接在控制台可以使用到的功能,包括告警监控、数据加工、重建索引、仪表盘订阅、聚集加工、各类数据源导入、智能巡检任务、和日志投递等。
接入层:接入层使用Nginx和CGI对外提供服务,具有高可用,地域化部署等特性。
API/SDK/Terraform/控制台:在用户侧,可以使用控制台对各类任务进行管理,对于不同的任务提供了定制化的界面和监控,同时也可以使用API、SDK、Terraform对任务进行增删改查。
任务调度框架设计要点
异构任务模型抽象
调度服务框架
大规模任务支持
服务高可用设计
任务模型抽象
对于告警监控、仪表盘订阅、聚集加工等需要定时执行的任务,抽象为定时任务,支持定时和Cron表达式设置。
对于数据加工、索引重建、数据导入等需要持续运行的任务,抽象为常驻任务,这类任务往往只需要运行一次,可以有也可以没有结束状态。
调度服务框架
任务的调度主要在Worker层来实现,每个Worker负责拉取对应Partitions的任务,然后通过JobLoader对任务进行加载,注意:这里只会加载当前Worker对应Partitions的任务列表,然后Scheduler对任务进行调度的编排,这里会涉及常驻任务、定时任务、按需任务的调度,Scheduler将编排好的任务发送到JobExecutor进行执行,JobExecutor在执行的过程中需要实时对任务的状态进行持久化保存到RedoLog中,在下次Worker升级重新启动的过程中,需要从RedoLog中加载任务的状态,从而保证任务状态的准确性。
大规模任务支持
Worker与Partition的对应关系并非一成不变,是一个动态的映射,在Worker重启或者负载较高时,其对应的Partition会迁移到其他的Worker上,所以Worker需要实现Partition的移入和移出操作。
任务数量增加的时候,因为有Partition这个中间层,只需要增加Worker的数量就可以满足任务增长时的需求,达到水平扩展的目的。增加新Worker后,可以分担更多的Partition。
服务高可用设计
发布流程:
从编译到发布全Web端白屏化操作,模板化发布,每个版本都可跟踪、回退。
支持集群粒度、任务类型粒度的灰度控制,在发布时可以进行小范围验证,然后全量发布。
运维流程:
提供内部运维API、Web端操作,对于异常Job进行修复、处理。减少人工介入运维。
On-Call:
在服务内部,我们开发了内部巡检功能,查找异常任务,例如某些任务启动时间过长、停止时间过长都会打印异常日志,可以对异常日志进行跟踪和监控。
通过异常日志,使用日志服务告警进行监控,出现问题可以及时通知运维人员。
任务监控:
用户侧:在控制台我们针对各类任务提供了监控仪表盘和内置告警配置。
服务侧:在后台,可以看到集群粒度任务的运行状态,便于后台运维人员进行服务的监控。
同时,对于任务的执行状态和历史都会存入特定的日志库中,以便出现问题时进行追溯和诊断。
典型任务:聚集加工
自动重试
如果实例执行失败(例如权限不足、源库不存在、目标库不存在、SQL语法不合法),系统支持自动重试
手动重试
动态任务类型:增加对于动态任务类型的支持,例如更复杂的具有任务间依赖关系的任务调度。
多租户优化:目前对于任务使用简单的Quota限制,未来对多租户的QoS进行的进一步细化,以支持更大的Quota设置。
API优化、完善:目前的任务类型也在快速更新中,任务API的迭代速度还有些差距,需要增强任务API的优化,达到增加一种任务类型,不需要修改或者少量更新API的目的。
推荐阅读
GTS云巧乘风者征文大赛上线!
云巧是“组装式应用”理念的落地,助力大家提升交付速度,提高交付质量,降低用工成本。参加云巧征文大赛,不仅可以让专业导师团评估,更有888元猫超卡和天猫精灵Sound等你来~前100名参加就可获得38元天猫超市卡哦,先到先得!
点击阅读原文查看详情。