浅谈工作流调度系统

转自 http://ju.outofmemory.cn/entry/221885


每个公司都有自己的一套或者多套调度系统,从简单到复杂,满足各种定制化的需求。

Crontab任务调度

在没有工作流调度系统之前,公司里面的任务都是通过crontab来定义的,时间长了后会发现很多问题:

  • 大量的crontab任务需要管理
  • 任务没有按时执行,各种原因失败,需要重试
  • 多服务器环境下,crontab分散在很多集群上,光是查看log就很花时间

于是,出现了一些管理crontab任务的调度系统。

CronHub

CronHub 是暴风影音的马晨开源的时间调度系统。CronHub通过web界面来管理分散在不同机器上的crontab任务。详见: Cronhub 开源的时间调度系统 

CronHub的UI: 
CronHub

可是一旦任务之间是有依赖关系的,Crontab就没有办法满足需求了。只能通过时间顺序,或者设计zk/文件等通知机制,或者通过shell/python脚本将任务串起来组成一个DAG图。等任务变多,会发现依赖关系的定义,修改很复杂,不够直观。于是出现了基于工作流的调度系统。

CronWeb

CronWeb 也是类似的系统

CronWeb的UI: 
CronWeb

工作流调度系统

在很多公司,随着处理的数据量增长,需要管理的工作流也变得越来越大,里面充斥着大量的ETL任务:有些依赖某个时间点去执行,有些依赖数据或者外部的事件来执行。工作流中的有些任务会失败,需要有重试和报警功能,而不是等到整个工作流失败才发现问题。

总的来说,一个 workflow scheduler system需要的主要功能有:

  • DAG定义 (DAG的定义方式:表达式,脚本定义,通过WEB UI定义;还需要支持子DAG)
  • 执行节点 (节点类型:unix cmd,shell,python,mapreduce, logging etc…)
  • 节点控制(ignore, retry, suspend, run now, test mode)
  • Metrics (需要对比一段时间内任务的运行时间)
  • Monitor (失败策略,报警通知功能)
  • CLI & Web UI (查询 workflow 执行情况,以及简单的控制)

Hadoop工作流引擎

OOZIE

Oozie是一个管理hadoop任务的工作流/协调系统。Oozie工作流中拥有多个Action,如Hadoop Map/Reuce job,Hadoop Pig job等,所有的Action以有向无环图(DAG Direct Acyclic Graph)的模式部署运行。详见: Hadoop工作流调度系统Oozie

Oozie的优点是与Hadoop生态圈结合紧密,比如:

  • 有MapReduce的Action,定义一个mapreduce任务很方便,而且可以直接通过job id关联到hadoop history页面
  • Oozie任务的资源文件都必须存放在HDFS上
  • Action也方便扩展,比如添加自定义的任务类型或者报警方式

缺点是通过XML文件来定义DAG依赖,虽然支持的功能很多,比如分支,ok,failed节点,但是总感觉定义过于复杂,维护成本高。

Oozie的UI: 
OOZIE

Oozie目前是Hadoop生态圈工作流调度事实上的标准,很多公司都在使用。其实,很难用,UI只能查看,不能进行任何操作。好在社区出现了 HUE ,可以弥补oozie的不足。

HUE 是一个开源的Apache Hadoop UI系统,最早是由Cloudera Desktop演化而来,由Cloudera贡献给开源社区,它是基于Python Web框架Django实现的。通过使用Hue我们可以在浏览器端的Web控制台上与Hadoop集群进行交互来分析处理数据,例如操作HDFS上的数据,运行MapReduce Job等等。

HUE提供了一个Oozie编辑器,可以通过仪表板提交和监控Workflow、Coordinator和Bundle。

HUE的UI: 
HUE

AZKABAN

Azkaban是由Linkedin开源的一个批量工作流任务调度器。用于在一个工作流内以一个特定的顺序运行一组工作和流程。Azkaban定义了一种KV文件格式来建立任务之间的依赖关系,并提供一个易于使用的web用户界面维护和跟踪你的工作流。详见: 工作流调度器Azkaban

Azkaban和Oozie一样,也属于Hadoop生态圈。它的DAG定义方式比Oozie简单很多,在properties文件里面可以通过dependencies指定任务的上游依赖。Azkaban支持可插拔的扩展插件,方便扩展,比如支持pid,hive等。

Azkaban的特点是所有的任务资源文件都需要打成一个zip包上传。这个在资源文件较大的时候不是太方便,当前也可以进行扩展,比如存放在HDFS上,任务实际运行的时候才拉到本地。

Azkaban的UI: 
AZKABAN

ZEUS

Zeus 是Alibaba开源的一个完整的Hadoop的作业平台,用于从Hadoop任务的调试运行到生产任务的周期调度。

宙斯支持任务的整个生命周期。从功能上来说,支持: 
* Hadoop MapReduce任务的调试运行 
* Hive任务的调试运行 
* Shell任务的运行 
* Hive元数据的可视化查询与数据预览 
* Hadoop任务的自动调度 
* 完整的文档管理

Zeus是针对Hadoop集群任务定制的,通用性不强。

基于Python的工作流引擎

基于Python的工作流引擎优点是:

The DAG definition is code

因此可维护性,版本管理,可测性和协作性更好。

dagobah

dagobah 是一个Python写的基于DAG的任务调度系统。Dagobah可以使用Cron语法调度周期性任务,任务之间可以定义依赖关系。Dagobash可以支持重试某个失败的任务,并在任务结束或失败的后发送汇总邮件,跟踪任务的输出log,持久化到不同的后端。Dagobash是一个相当轻量级的调度系统。

dagobah可以通过Web UI通过拖拉的方式操作dag,也支持直接通过代码定义:


   
   
  1. from dagobah import Dagobah
  2. from dagobah . backend . base import BaseBackend
  3. my_dagobah = Dagobah ( BaseBackend ())
  4. my_dagobah . add_job ( ’My Job’ )
  5. my_job = my_dagobah . get_job ( ’My Job’ )
  6. my_job . add_task ( ’python required_task.py’ , ’Required Task’ )
  7. my_job . add_task ( ’python dependent_task.py’ , ’Dependent Task’ )
  8. my_job . add_dependency ( ’Required Task’ , ’Dependent Task’ )
  9. my_job . schedule ( ’0 10 * * *’ )

dogobah的UI: 
dogobah

Luigi

Luigi 是Spotify开源的,关注流程复杂的长时间运行的批次任务,例如Hadoop任务,推送数据,或者从数据库拉数据的任务,机器学习算法任务等。它能处理依赖关系,工作流关系,可视化等。它内置对Hadoop的支持。

一个hadoop上运行的wordcount任务定义如下:


   
   
  1. import luigi
  2. import luigi . contrib . hadoop
  3. import luigi . contrib . hdfs
  4. class InputText ( luigi . ExternalTask ):
  5. """
  6. This task is a :py:class:`luigi.task.ExternalTask` which means it doesn't generate the
  7. :py:meth:`~.InputText.output` target on its own instead relying on the execution something outside of Luigi
  8. to produce it.
  9. """
  10. date = luigi . DateParameter ()
  11. def output ( self ):
  12. """
  13. Returns the target output for this task.
  14. In this case, it expects a file to be present in HDFS.
  15. :return: the target output for this task.
  16. :rtype: object (:py:class:`luigi.target.Target`)
  17. """
  18. return luigi . contrib . hdfs . HdfsTarget ( self . date . strftime ( '/tmp/text/%Y-%m-%d.txt' ))
  19. class WordCount ( luigi . contrib . hadoop . JobTask ):
  20. """
  21. This task runs a :py:class:`luigi.contrib.hadoop.JobTask`
  22. over the target data returned by :py:meth:`~/.InputText.output` and
  23. writes the result into its :py:meth:`~.WordCount.output` target.
  24. This class uses :py:meth:`luigi.contrib.hadoop.JobTask.run`.
  25. """
  26. date_interval = luigi . DateIntervalParameter ()
  27. def requires ( self ):
  28. """
  29. This task's dependencies:
  30. * :py:class:`~.InputText`
  31. :return: list of object (:py:class:`luigi.task.Task`)
  32. """
  33. return [ InputText ( date ) for date in self . date_interval . dates ()]
  34. def output ( self ):
  35. """
  36. Returns the target output for this task.
  37. In this case, a successful execution of this task will create a file in HDFS.
  38. :return: the target output for this task.
  39. :rtype: object (:py:class:`luigi.target.Target`)
  40. """
  41. return luigi . contrib . hdfs . HdfsTarget ( '/tmp/text-count/%s' % self . date_interval )
  42. def mapper ( self , line ):
  43. for word in line . strip (). split ():
  44. yield word , 1
  45. def reducer ( self , key , values ):
  46. yield key , sum ( values )
  47. if __name__ == '__main__' :
  48. luigi . run ()

Luigi的UI: 
Luigi

Pinball

Pinball 是Pinterest开源的扩展性较好的工作流系统。Pinball的架构是一种master-worker模式,master节点负责管理任务调度,worker节点是无状态的。Pinball无缝集成了Hadoop/Hive/Spark等。

Pinball提供了自动重试,单任务邮件报警,运行时替换,任务优先级,过载策略等功能。

Pinball的UI: 
Pinball

Airflow

Airflow 是Airbnb开源的DAG任务调度系统,用于管理,调度和监控工作流。它与Luigi,Pinball很像。后端是基于Flask,Celery,RabbitMQ/Redis。

Airflow工作流的定义:


   
   
  1. """
  2. Code that goes along with the Airflow located
  3. [here](http://pythonhosted.org/airflow/tutorial.html)
  4. """
  5. from airflow import DAG
  6. from airflow . operators import BashOperator
  7. from datetime import datetime , timedelta
  8. seven_days_ago = datetime . combine ( datetime . today () - timedelta ( 7 ),
  9. datetime . min . time ())
  10. default_args = {
  11. 'owner' : 'airflow' ,
  12. 'depends_on_past' : False ,
  13. 'start_date' : seven_days_ago ,
  14. 'email' : [ '[email protected]' ],
  15. 'email_on_failure' : False ,
  16. 'email_on_retry' : False ,
  17. 'retries' : 1 ,
  18. 'retry_delay' : timedelta ( minutes = 5 ),
  19. \ # 'queue' : 'bash_queue' ,
  20. \ # 'pool' : 'backfill' ,
  21. \ # 'priority_weight' : 10 ,
  22. \ # 'schedule_interval' : timedelta ( 1 ),
  23. \ # 'end_date' : datetime ( 2016 , 1 , 1 ),
  24. }
  25. dag = DAG ( 'tutorial' , default_args = default_args )
  26. \ # t1 , t2 and t3 are examples of tasks created by instatiating operators
  27. t1 = BashOperator (
  28. task_id = 'print_date' ,
  29. bash_command = 'date' ,
  30. dag = dag )
  31. t1 . doc_md = """\
  32. \#### Task Documentation
  33. You can document your task using the attributes `doc_md` (markdown),
  34. `doc` (plain text), `doc_rst`, `doc_json`, `doc_yaml` which gets
  35. rendered in the UI's Task Details page.
  36. ![img](http://montcs.bloomu.edu/~bobmon/Semesters/2012-01/491/import%20soul.png)
  37. """
  38. dag . doc_md = __doc__
  39. t2 = BashOperator (
  40. task_id = 'sleep' ,
  41. depends_on_past = False ,
  42. bash_command = 'sleep 5' ,
  43. dag = dag )
  44. templated_command = """
  45. {% for i in range(5) %}
  46. echo " {{ ds }} "
  47. echo " {{ macros . ds_add ( ds , 7 )}} "
  48. echo " {{ params . my_param }} "
  49. {% endfor %}
  50. """
  51. t3 = BashOperator (
  52. task_id = 'templated' ,
  53. depends_on_past = False ,
  54. bash_command = templated_command ,
  55. params ={ 'my_param' : 'Parameter I passed in' },
  56. dag = dag )
  57. t2 . set_upstream ( t1 )
  58. t3 . set_upstream ( t1 )

Airflow的功能很多,对于工作流可以支持Cron语法调度,失败重试策略,各种任务依赖调度策略等。

Airflow的一大亮点是backfill功能,对于数据仓库这种应用很有帮助,可以指定开始时间,将一个时间范围的任务重跑。Airflow还提供了丰富的命令行CLI和UI供操作。

Airflow通过Celery来实现分布式调度,架构的设计上很清晰,利于扩展。

Airflow的UI: 
Airflow

其他

工作流调度系统很多,有人做了统计:

没有一个系统是能完全满足需求的,每个公司都会根据自己的需求进行定制化调度,选择一个架构合理,利于扩展的开源系统修改是不错的选择。

作者:日拱一卒
技术之路永无止境,每天进步一点点…
原文地址: 浅谈工作流调度系统, 感谢原作者分享。


猜你喜欢

转载自blog.csdn.net/frone/article/details/82218370