Apache Mesos(10)-使用Chronos创建复杂任务

目录
  1. 使用Chronos创建复杂任务
  2. 查看任务状态

作者:杨冬 欢迎转载,也请保留这段声明。谢谢!
出处:https://andyyoung01.github.io/http://andyyoung01.16mb.com/

前一篇文章我们创建了简单的、独立的不依赖于其它任务的任务。它与我们非常熟悉的Linux系统上的Cron守护进程非常类似。Chronos也有能力创建复杂的、依赖于其它任务的任务。这个任务只有当它的父任务成功完成后才执行。这样的典型的任务包括用于数据处理和分析的ETL任务。

使用Chronos创建复杂任务

Chronos可以创建一个复杂的任务,它至少对其它任务有一个依赖(它只在它所依赖的父任务成功完成后运行)。这可以是一个类似于通过extract-transform-load (ETL)管道进行数据处理的任务,它可以每小时、每天或者每周运行一次。一个典型的ETL任务做如下的工作:

  • Extract提取数据。
  • Transform转换数据,将数据存储为更适合分析的格式。
  • Load装载数据,将数据保存到目标存储位置。

在Chronos里,依赖其它任务的任务的配置文件里并不包括schedule字段,而是指定一个或多个父任务(使用parents字段),父任务成功完成之后此任务才能开始运行。下图描述里一个在Chronos里的ETL任务,注意schedule和parents字段的区别:
“一个复杂的Chronos任务”
下面我们看一个实例:这个ETL计划任务对《War and Peace》书中的单词进行统计,统计出现频率最高的20个单词。这个例子使用了Spark。它的任务依赖如下图所示:
“ETL Chronos任务”
由于本篇主要是关于Chronos的,所以Spark等的安装配置及如何编写Spark的map/reduce程序本篇不再详细说明,上图中的HDFS我们也用本地文件系统代替,这样使我们的关注点集中在Chronos这里。

如何在Mesos集群上运行Spark,请参考官方文档

首先编写第一个任务的JSON文件:

01-download-war-and-peace.json
1
2
3
4
5
6
7
8
9
{
"name": "download-war-and-peace",
"description": "Download the text of War and Peace from Project Gutenberg.",
"schedule": "R1//PT1M",
"command": "cd $MESOS_SANDBOX && cp 2600-0.txt /tmp/warandpeace.txt",
"uris": [
"http://www.gutenberg.org/files/2600/2600-0.txt"
]
}

上面的代码清单从Project Gutenberg下载了War and Peace的文本,并将其存储到Mesos的工作目录中。在ETL任务的下一步将进行Spark的map/reduce任务,来计算文件中每个单词的出现次数。下面的代码清单创建了第二个Chronos任务,这次在parents字段中指定了前一个任务(download-war-and-peace)。

02-spark-wordcount-job.json
1
2
3
4
5
6
7
8
9
10
11
12
{
"name": "war-and-peace-wordcount-spark-job",
"description": "Use Spark to count all the words in War and Peace",
"parents": ["download-war-and-peace"],
"command": "/opt/spark-2.0.0-bin-hadoop2.7/bin/spark-submit spark-wordcount-master/war-and-peace-wordcount_2.10-0.1.1-SNAPSHOT.jar ${basepath}",
"uris": [
"https://github.com/andyyoung01/spark-wordcount/archive/master.zip"
],
"environmentVariables": [
{ "name": "basepath", "value": "/tmp" }
]
}

上面的代码清单从github下载打包好的jar文件,并从工作目录中读取上一步下载好的文本文件。为了在Mesos UI中将结果显示出来,在下一步读取Spark的统计结果,排序,并且取得前20行。类似于上面的步骤,这里也指定了parents字段来确定此任务对前一任务的依赖。

03-load-results-job.json
1
2
3
4
5
6
7
8
9
{
"name": "load-war-and-peace-word-counts",
"description": "Read the output from HDFS and send it to stdout",
"parents": ["war-and-peace-wordcount-spark-job"],
"command": "cat ${basepath}/result/part-* | sort -t, -rnk2 | head -20",
"environmentVariables": [
{ "name": "basepath", "value": "/tmp" }
]
}

好了。上面三个任务运行了一个ETL管道,它统计了War and Peace里出现频率最高的20个单词。下面的脚本文件可以批量将三个任务提交到Chronos里:

create-jobs.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash
if [[ ! $# > 0 ]]; then
echo "Usage: $0 <http://chronos-host:4400>"
echo
exit 1
else
CHRONOS_URL=$1
fi
DIR=$(dirname "${BASH_SOURCE}")
CURL=""
for job in "${DIR}"/*.json; do
echo -n "Creating job ${job} in Chronos..."
if grep \"schedule\" "${job}" > /dev/null; then
curl -H 'Content-Type: application/json' -d @${job} ${CHRONOS_URL}/scheduler/iso8601
[[ $? == 0 ]] && echo "Done." || echo "Error!"
elif grep \"parents\" "${job}" > /dev/null; then
curl -H 'Content-Type: application/json' -d @${job} ${CHRONOS_URL}/scheduler/dependency
[[ $? == 0 ]] && echo "Done." || echo "Error!"
else
echo "Error: could not determine job type for '${job}'"
fi
done

将上面创建的3个json文档放在当前目录下,并确保目录中没有其它的json文件。然后使用如下命令调用上述脚本:

$ create-jobs.sh http://your-chronos-ip:4400

查看任务状态

在运行了上述命令后,可以在Chronos的web界面中查看任务的运行状态及依赖关系:
“Chronos任务状态”
“Chronos任务依赖关系”
在Mesos的界面中也可以查看任务的状态,如下图:
“Mesos任务状态”
上图点击Sandbox进入该任务的工作目录后,可以继续查看任务的stdout:
“Mesos任务状态”
最后显示出Spark的运行结果,统计出该书中出现频率最高的20个单词:
“任务结果”

本文旨在学习Chronos的复杂任部署,文中对于Spark进行了简化的部署,省略了HDFS的部署,关于Spark及HDFS的部署请参考官方文档。