最近在构思一个作业调度系统(Job scheduling system), 其实作业调度系统也不是什么新东西, 很多大学的超级计算中心和气象中心都有这种系统, 最典型的开源软件架构是Torque加Maui, 这两个软件都是由Cluster Resources Inc维护的开源软件, 在维基百科上列出了一堆软件(http://en.wikipedia.org/wiki/Category:Job_scheduling).
我所考虑的是作业调度系统, 不是面向科学计算, 而是针对金融行业日结月结作业或者DW/BI系统的refresh, 这类作业调度系统和气象中心的作业调度系统有很大的不同. 具体不同之处, 我就不列了. 这类调度系统的特点是, 作业数量很多, 主要是来回导数据和运行stored procedure. 在我看来, 这些操作, 由大到小可以分为3个层次, Cycle->Batch->Job. 先给出我自己对这3个概念的定义.
Cycle: 一个完整的刷新过程, 比如EOD(日结) refresh, 就可以算作一个cycle
Batch: 每次单独被调起的刷新过程段, 就是一个batch. 一个Cycle可以包含多个batch, 比如CRM batch和ERP batch.
Job: 一个不能再分解的作业, 比如一个ETL Job.
构思中的系统为Batch级的调度系统, 它将不涉及Cycle级别的管理, 因为, 在我看来Cycle级的管理, 多是来维护Batch之间的依赖关系, 通常一个企业的Batch不会很多, 所以维护起来并不复杂, 可以写一个简单的shell, 或者用一些可视化的control flow工具完成, 比如微软SSIS的 control flow, IBM DataStage(以下有时会简称为ds) 的Job Sequence, 或者CA的Autosys来管理. 而Batch内部的调度要比这个复杂得多了去, 需要一个专门的系统来管理.
这个Batch级的调度系统, 具有如下特性:
1. 提供水平扩展能力(即可以动态增加或减少工作节点Node)
2. 提供Load Balance特性(*考虑到LB算法的复杂性, 可先采用一个高效但不准确的算法)
3. 如果某个节点出现故障, 作业将自动转移到其他节点上运行.
4. 提供出错重试机制(能做到一定程度的High Availability)
5. 超时告警机制
6. Job调度设置的版本管理功能(这个我认为很重要, 如果Job调度调整错了, 作为应急, 可以很容易恢复到以前的版本. )
想法由来:
金融行业日结月结的数据量很大, 花费时间一般都很长. 而在DW/BI系统中, 留给DW/BI的刷新窗口往往也不会很大, 同时业务对于DW/BI系统的实时性要求也越来越高了, 除了传统的EOD batch, 有的还需要mini batch和micro batch. 这时候一个高效可靠的调度就显得尤为重要了. 另外,在一些大公司中, 往往会使用多种数据库(SQL Server, Oracle, MySQL), 多种ETL工具(比如SQL Server SSIS,Datastage). 这些都给batch调度带来了不大不小的困难.
触发这个构思的最直接的原因, 公司采用了国内一个系统服务商开发的调度系统, 这个系统不太稳定, 而且使用超复杂. 下面是我公司的情况, 故事挺长的, 建议读者略过.
公司以前的DW / BI系统调度是通过Shell脚本来实现的
(简单讲, 就是用Shell来调用datastage的dsjob命令
或者sqlplus), 随着job越来越多, batch的时间越来
越长, 都快要突破留给DW / BI的时间窗口了. 缩短
batch一个很简单的方法是,再增加一台datastage服务
器, 这样2台Datastage并行运行, 应该会快一些,
同时一台datastage server宕掉后, 如果能将所有
ds job切换到另一台, 也算做到了高可用性(HA),
这些shell开发的调度程序难以支持这种需求. 为
此, 公司引进了一国内系统服务商自己研发的产品,
这里就不点名了, 如果有兴趣的话, google
搜 " 企业ETL服务管理平台软件 " , 该产品号称支持:
* 动态负载均衡(Load Balance)
* 拥有横向扩展能力(High Scalability)
* 可以进行集群管理
经过一段时间的使用, 发现这个软件真不咋样,
1 . 用户体验不友好, 不是一般的不友好.
2 . 系统稳定性不行, 有几次无法被自动调起
(这有点讽刺意味, 宣称提供HA特性的系统,
本身却不够稳定)
3 . 该软件是通过不断扫描(或监听)外部状态,
来启动batch. 而没有任何机制, 来实现
batch暂停, batch终止.
4 . 该软件的维护起来真困难, 需要多一套配置
(曰为base配置),
5 . 该软件权限管理比较别扭, 这将直接影响到
调度作业修改的流程控制
另外, 更深一些, 它是假集群, 在某些情形下,
会造成很严重的后果, 简单列几条:
1 . 比如在生产环境中, 可以部署2个该软件服务
端, 同时只有一个服务端是主服务端(master),
另一个是standby, 这些服务端通过tcp通讯
来完成心跳测试的. 很明显, 这种架构,
存在假死现象. 即master端和standby端之间,
如果出现网络异常情况, 这个standby服务端就
会切换成主服务端, 这时候, 整个环境会有2个
主服务端, 不敢想象这种情况下调度会是什么
样子, 估计调度会乱作一团的. (建议该厂家
研究一下真正cluster软件是如果测心跳的,
比如SQL Server Cluster或Oracle RAC,
其实安装一下这些系统, 就能猜出一二)
2 . 再比如, 开始时由服务端A作为主服务端, 调起
了Job_1, 未等Job_1结束, 服务端A宕掉, 服务
端B被切换成主服务端, 这时, Job_1就是一个
孤儿job, 该Job有可能正常运行结束, 也有可
能运行失败. 一旦出现了孤儿job, 该软件采用
的是简单重调方式, 它会再次调起Job_1. 如果
Job_1是不可重调的, 这可能会引起严重的问题.
3 . 另外, 这种宣称的集群, 其实不应该算作集群.
我认为一个集群, 应该是作为一个整体向用户
提供计算能力, 从用户角度看, 集群就像是一个
单一的计算机. 而该软件在生产环境中, 可以部
署多个服务端, 却又不能提供一个统一的访问
渠道来和这几个服务端通讯.
# ##############
Job调度模型
本调度框架构思来自于高速公路收费口排队. 姑且叫做Batch调度之高速公路收费口调度模型. 在讲述模型之前, 先做一些假设:
假设1: 有2条京沪高速公路, 不是2车道, 是复线, 比如路R1和路R2, 分别有3个收费口和4个收费口, 也就是说这两条路的处理能力不一样. (构建一个多节点的情形, R1节点同时能处理3个Job, 而R2同时能处理4个Job)
假设2: 通向R1收费口的路(gateway), 宽为5米, R1的所有收费口都共用这5米的入口; 通向R2收费口的路宽为6米, (每个节点的处理能力不同)
假设3: 有些收费口只允许小汽车通过, 有的允许大客车和大货车通过, 有的不限制汽车的类型. (比如SSIS Job只能在windows节点上运行, 而不能再linux上运行)
情景模拟一下, 如果你是一个司机的话, 你是如何选择收费口呢? 你需要看看你开的是什么车, 哪些收费口允许你的车通过; 如果R1和R2上还有其他车在交费,它们将占用一定的路宽, 你需要再看看你的车宽度, 看看能不能转钻过去到达收费口. 如果你没有喝醉酒, 你应该会选择一个合适的收费口.
现在春节刚过, 相信不少朋友又一次领略了铁老大的威武. 在我记忆中, 最气愤的一次购票经历是, 有一次在北京转车, 火车站广场露天排队, 好几个长龙, 我就跟在一个队伍的后边排着, 大概排了两三个小时, 好不容易快到窗口了, 队伍前面一阵骚乱, 原来这个窗口卖票员要吃午饭, 窗口就这样关啦. 我和我后面的很多人算是白排了.
构思中的调度系统, 并没有窗口排队概念, 而是采用即时任务分派策略(Just-in-time dispatch), 这样做将比窗口排队方式好很多. 如果你采用排队方式, 当某个节点宕掉, 你需要考虑排这个节点上的任务该如何分配到其他节点上, 要做到公平, 算法恐怕会有点复杂.
软件结构
程序:
1. Batch级的命令行程序(执行启动/暂停/继续/终止操作,以及查询batch的所处状态)
2. 静态模型的版本控制工具
常驻进程:
1. Job分派进程
2. 一个类似cron的进程, 不断扫描event是否可以触发
3. 测超时的进程
外部需扩展
1. 超时算法由外部程序扩展, 推荐的算法是runtime>max(timeout_threshold,average_time*ratio)
2. 每次Batch启动时候, 可以一个XML字符串的形式给batch附加一些全局信息, 比如交易日期等等
3. 每个job, 在执行前调命令和执行命令以及执行后调命令, 都给命令附加额外的参数, 这些参数包括, job的所有静态和动态信息, 以及batch的信息.
操作说明
常见的batch驱动机制包括: 被动被call起来, 定时被call起来, 还有一种情形是, 满足某个条件后, Batch应该被call起来, (比如, 当FTP文件下载完毕). 目前本调度程序不仅支持第一种情形, 对于后面2种情形, 可以通过定时事件(cron_event)来完成. 定时启动, 就不说了, 对于对于FTP下载完成等启动, 也可用cron来扩展, cron任务来监控某个文件是否下载完成(如果它的md5值和源头那边一致, 就认为文件传输完毕), 待下载完成后, 调用batch.
batch级的操作
1. 启动一个batch(指定batch级别的Indicator)
2. 暂停一个batch
3. 继续运行一个batch
4. 强制结束一个batch
5. 强制重新开始一个的batch(或者不提供强制重启, 提供另一个reset命令, 强制重启=reset+启动)
6. 查询一个Batch的运行状态
如何一个启动Batch:
batch_manage run Batch_ID='Batch_ERP' Cycle_No='Cycle_20101215' Frequency='D' BatchIndictor='''<batchIndicator transactionDate='20101215' something='hello' />'''
数据模型
在开始介绍数据模型之前, 先看看一个Job会有什么样的属性, 这样有利于我们更好地管理Job.
首先Job会有一个Batch属性, 这样当我们启动一个batch时候, 就知道我们该call哪些job.
其次, Job运行会有频率属性的, 比如job A在天结/周结/月结都需要运行, 而job B只在月结是运行, 显然一个job可能有一个或多个频率值.
为了很好的组织Job, 我们引入了Job_Group概念, 作为Job的类型归类, 比如我们可以有一个Datastage group, 作为所有datastage etl job的归类, SSIS group 作为所有ssis job的归类.
数据模型包括4个部分, 分别为Batch定义模型部分, 运行时模型, 运行时归档模型, Batch定义归档模型.
Batch定义模型是整个系统的基础, 它定义了Batch级以及Job级别的静态模型; 运行时模式, 顾名思义, 保存着batch运行时的动态信息, batch结束后, 所有的动态信息被转存到运行时归档模型中. Batch定义归档模型, 是考虑到我们需要对Batch调度调整进行版本管理引入的, 也就是保存着Batch定义模型的revise数据.
我手头上PowerDesigner/ERWin, 甚至连Visio都没有, 只好用Excel来做建模工作, 所以表的relationship没有办法直观地表达出来, 需要看字段外键. 这里只贴出Batch定义模型和运行时模型, 其他2个部分其实仅仅是这2个部分的简单扩展.
Batch定义模型部分
Node_Static(节点表)
Frequency_Static(频率表)
Job_Group_Static(job组别)
Batch_Static(Batch主表)
Job_Static (任务主表), 这是一个宽表, 字段很多.
Job_Timeout_Def_Static
Job_Depend_Static,
这个表有一个四态控制字段Control_Flag, Control_Flag=Successful 表示, 前一个job必须运行成功, 才能运行后续job, Control_Flag=Failed, 表示前一个job必须失败, 才能运行后续job, Control_Flag=Completed, 表示只要前一个job运行结束(不管是成功还是失败), 后续job都可以运行, Control_Flag=Disable, 表示不考虑这个依赖.
Cron_Events_Static(类似cron的定义表)
Mutex_Lock_Static
Job_Event_Handler
这个表定义每个job启动/结束(包括成功和失败), 会触发哪些事件, 我们可以在这里将job的运行状态写到一个外部log文件, 当然本调度系统应该默认会将这些重要的log写到数据库中.
运行时模型
Batch_status_rt
Batch_Operation_rt
Job_status_rt(1个job最多一条记录)
Job_operation_rt表
Mutex_Lock_Status_rt
Exception_rt表(记录运行时的异常)
整个数据模型确立后, 其实这个batch调度系统在我脑中已经成形了, 剩下的只是花时间实现了. 当然, 我现在没有业余时间来实现这个东西, 期望能在一个新的岗位上有机会完成它, 如果能用python, 那简直太棒了. 如果你正在搞类似的东西, 希望这篇文章会对你有启发.
所有评论(0)