Airflow安装详细介绍以及入门Demo

Airflow 是什么

Airflow 是 Airbnb 开发的用于工作流管理的开源项目,自带 web UI 和调度。现在 Apache 下做孵化,地址是 https://github.com/apache/airflow

airflow

airflow

Airflow 解决什么问题

Airflow 主要解决的问题可以参考 Airbnb 官方的博客: airflow-a-workflow-management-platform,简单来说就是管理和调度各种离线定时 Job ,可以替代 crontab。

当 cron job 规模达到数百上千时,其对人的要求将会非常高的,如果你的团队经历过这样的事情,应该能体会其中痛苦,所以使用类似 airflow 这样的工具代替 cron 来做定时任务将会极大提高工作效率。

开始使用 airflow 之前需要知道和准备的

Airflow 在 pip 上已经更名为 apache-airflow,下载最新版请使用后者 pip install apache-airflow

Airflow 1.8 版本依赖的是 MySQL 5.6 以上,5.7 以下报 1071, u'Specified key was too long; max key length is 767 bytes,如果你使用 MySQL 作为你的 airflow backend 请升级你的 MySQL 到最新版。

MySQL 5.6 升级到 5.7 在使用 airflow 时会报 1146, u"Table 'performance_schema.session_variables' doesn't exist",执行 mysql_upgrade -u root -p --force 解决。

Airflow 的 mysql driver 使用的是 mysqlclient mysql://root:@127.0.0.1/sqlalchemy_lab?charset=utf8,如果使用其他 driver 将报 syntax error。

基础概念

Airflow 中最基本的两个概念是:DAG 和 task。DAG 的全称是 Directed Acyclic Graph 是所有你想执行的任务的集合,在这个集合中你定义了他们的依赖关系,一个 DAG 是指一个 DAG object,一个 DAG object 可以在 Python 脚本中配置完成。

比如一个简单的的 DAG 包含三个 task:A、B、C,A 执行成功之后 B 才能执行,C 不依赖 A 和 B 即可执行。在这个简单的 DAG 中 A B C 可以是任何你想要执行的任务。

DAG 的定义使用 Python 完成的,其实就是一个 Python 文件,存放在 DAG 目录,Airflow 会动态的从这个目录构建 DAG object,每个 DAG object 代表了一个 workflow,每个 workflow 都可以包含任意个 task。

安装和使用

Airflow 是基于 Python 构建的,可以很容易用 pip 安装使用,pip install apache-airflow,默认情况下 airflow 会在 ~/airflow 目录存放相关配置。

安装过程中可能会出现报错的情况,此时我们查看错误log,发现是让我们设置环境变量,接下来我们需要做的就是

vim ~/.bash_profile 
export SLUGIFY_USES_TEXT_UNIDECODE=yes
source ~/.bash_profile 

Airflow 提供了一些列命令来完成 airflow 的初始化工作来和它的正确使用。

# 在 airflow 目录初始化数据库和 airflow 配置
airflow initdb
# 启动 airflow web
airflow webserver
# 开始调度
airflow scheduler复制代码

更详细的信息请参考文档 airflow.incubator.apache.org/

 

示例管道定义

以下是基本管道定义的示例。如果这看起来很复杂,请不要担心,下面将逐行说明。

"""
Code that goes along with the Airflow tutorial located at:
https://github.com/apache/airflow/blob/master/airflow/example_dags/tutorial.py
"""
from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from datetime import datetime, timedelta


default_args = {
    'owner': 'airflow',
    'depends_on_past': False,
    'start_date': datetime(2015, 6, 1),
    'email': ['[email protected]'],
    'email_on_failure': False,
    'email_on_retry': False,
    'retries': 1,
    'retry_delay': timedelta(minutes=5),
    # 'queue': 'bash_queue',
    # 'pool': 'backfill',
    # 'priority_weight': 10,
    # 'end_date': datetime(2016, 1, 1),
}

dag = DAG('tutorial', default_args=default_args, schedule_interval=timedelta(days=1))

# t1, t2 and t3 are examples of tasks created by instantiating operators
t1 = BashOperator(
    task_id='print_date',
    bash_command='date',
    dag=dag)

t2 = BashOperator(
    task_id='sleep',
    bash_command='sleep 5',
    retries=3,
    dag=dag)

templated_command = """
    {% for i in range(5) %}
        echo "{{ ds }}"
        echo "{{ macros.ds_add(ds, 7)}}"
        echo "{{ params.my_param }}"
    {% endfor %}
"""

t3 = BashOperator(
    task_id='templated',
    bash_command=templated_command,
    params={'my_param': 'Parameter I passed in'},
    dag=dag)

t2.set_upstream(t1)
t3.set_upstream(t1)

这是一个DAG定义文件

包围你的一件事(对于每个人来说可能不是很直观)是这个Airflow Python脚本实际上只是一个配置文件,将DAG的结构指定为代码。此处定义的实际任务将在与此脚本的上下文不同的上下文中运行。不同的任务在不同的时间点对不同的工作程序运行,这意味着此脚本不能用于在任务之间交叉通信。请注意,为此,我们有一个更高级的功能XCom

人们有时会将DAG定义文件视为可以进行实际数据处理的地方 - 事实并非如此!该脚本的目的是定义DAG对象。它需要快速评估(秒,而不是分钟),因为调度程序将定期执行它以反映更改(如果有的话)。

导入模块

Airflow管道只是一个Python脚本,恰好定义了Airflow DAG对象。让我们首先导入我们需要的库。

# The DAG object; we'll need this to instantiate a DAG
from airflow import DAG

# Operators; we need this to operate!
from airflow.operators.bash_operator import BashOperator

默认参数

我们即将创建一个DAG和一些任务,我们可以选择显式地将一组参数传递给每个任务的构造函数(这将变得多余),或者(更好!)我们可以定义一个默认参数的字典,我们可以可以在创建任务时使用。

from datetime import datetime, timedelta

default_args = {
    'owner': 'airflow',
    'depends_on_past': False,
    'start_date': datetime(2015, 6, 1),
    'email': ['[email protected]'],
    'email_on_failure': False,
    'email_on_retry': False,
    'retries': 1,
    'retry_delay': timedelta(minutes=5),
    # 'queue': 'bash_queue',
    # 'pool': 'backfill',
    # 'priority_weight': 10,
    # 'end_date': datetime(2016, 1, 1),
}
有关BaseOperator参数及其功能的更多信息,请参阅airflow.models.BaseOperator文档。

另外,请注意,您可以轻松定义可用于不同目的的不同参数集。一个例子是在生产和开发环境之间进行不同的设置。

实例化

我们需要一个DAG对象来嵌入我们的任务。这里我们传递一个定义的字符串dag_id,它作为DAG的唯一标识符。我们还传递我们刚刚定义的默认参数字典,并schedule_interval为DAG 定义1天。

dag = DAG(
    'tutorial', default_args=default_args, schedule_interval=timedelta(days=1)
)

任务

在实例化操作员对象时生成任务。从运算符实例化的对象称为构造函数。第一个参数 task_id充当任务的唯一标识符。

t1 = BashOperator(
    task_id='print_date',
    bash_command='date',
    dag=dag)

t2 = BashOperator(
    task_id='sleep',
    bash_command='sleep 5',
    retries=3,
    dag=dag)
请注意我们如何将从BaseOperator继承的bash_command所有运算符(retries)共同的运算符特定参数()和通用参数传递给运算符的构造函数。这比为每个构造函数调用传递每个参数更简单。另外,请注意在第二个任务中我们用retries参数覆盖参数3

任务的优先规则如下:

  1. 明确传递参数
  2. default_args字典中存在的值
  3. 运算符的默认值(如果存在)

任务必须包括或继承的参数task_idowner,否则气流将引发异常。

使用Jinja模板

Airflow利用Jinja Templating的强大功能, 为管道作者提供一组内置参数和宏。Airflow还为管道作者提供了定义自己的参数,宏和模板的钩子。

本教程几乎没有涉及在Airflow中使用模板进行操作的表面,但本节的目的是让您了解此功能的存在,让您熟悉双花括号,并指向最常见的模板变量:( 今天的“日期戳”)。{{ ds }}

templated_command = """
    {% for i in range(5) %}
        echo "{{ ds }}"
        echo "{{ macros.ds_add(ds, 7) }}"
        echo "{{ params.my_param }}"
    {% endfor %}
"""

t3 = BashOperator(
    task_id='templated',
    bash_command=templated_command,
    params={'my_param': 'Parameter I passed in'},
    dag=dag)

请注意,templated_command包含块中的代码逻辑,引用参数,如调用函数 ,并引用用户定义的参数。{% %}{{ ds }}{{ macros.ds_add(ds, 7)}}{{ params.my_param }}

paramsBaseOperator允许你传递的参数和/或对象字典来你的模板。请花点时间了解参数如何my_param通过模板。

文件也可以传递给bash_command参数,例如 bash_command='templated_command.sh',文件位置相对于包含管道文件的目录(tutorial.py在本例中)。这可能是出于许多原因,例如分离脚本的逻辑和管道代码,允许在用不同语言编写的文件中正确的代码突出显示,以及构造管道的一般灵活性。也可以将您定义template_searchpath为指向DAG构造函数调用中的任何文件夹位置。

使用相同的DAG构造函数调用,可以定义 user_defined_macros哪些允许您指定自己的变量。例如,传递dict(foo='bar')给此参数允许您在模板中使用。此外,指定 允许您注册自己的过滤器。例如,传递给此参数允许您在模板中使用。有关自定义过滤器的更多信息,请查看 Jinja文档{{ foo }}user_defined_filtersdict(hello=lambda name: 'Hello %s' % name){{ 'world' | hello }}

有关可以在模板中引用的变量和宏的更多信息,请务必阅读部分

设置依赖关系

我们有任务t1,t2和t3不相互依赖。以下是一些可以定义它们之间依赖关系的方法:

t1.set_downstream(t2)

# This means that t2 will depend on t1
# running successfully to run.
# It is equivalent to:
t2.set_upstream(t1)

# The bit shift operator can also be
# used to chain operations:
t1 >> t2

# And the upstream dependency with the
# bit shift operator:
t2 << t1

# Chaining multiple dependencies becomes
# concise with the bit shift operator:
t1 >> t2 >> t3

# A list of tasks can also be set as
# dependencies. These operations
# all have the same effect:
t1.set_downstream([t2, t3])
t1 >> [t2, t3]
[t2, t3] << t1
请注意,在执行脚本时,Airflow会在DAG中找到循环或多次引用依赖项时引发异常。

回顾

好吧,所以我们有一个非常基本的DAG。此时,您的代码应如下所示:

"""
Code that goes along with the Airflow tutorial located at:
https://github.com/apache/airflow/blob/master/airflow/example_dags/tutorial.py
"""
from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from datetime import datetime, timedelta


default_args = {
    'owner': 'airflow',
    'depends_on_past': False,
    'start_date': datetime(2015, 6, 1),
    'email': ['[email protected]'],
    'email_on_failure': False,
    'email_on_retry': False,
    'retries': 1,
    'retry_delay': timedelta(minutes=5),
    # 'queue': 'bash_queue',
    # 'pool': 'backfill',
    # 'priority_weight': 10,
    # 'end_date': datetime(2016, 1, 1),
}

dag = DAG(
    'tutorial', default_args=default_args, schedule_interval=timedelta(days=1))

# t1, t2 and t3 are examples of tasks created by instantiating operators
t1 = BashOperator(
    task_id='print_date',
    bash_command='date',
    dag=dag)

t2 = BashOperator(
    task_id='sleep',
    bash_command='sleep 5',
    retries=3,
    dag=dag)

templated_command = """
    {% for i in range(5) %}
        echo "{{ ds }}"
        echo "{{ macros.ds_add(ds, 7)}}"
        echo "{{ params.my_param }}"
    {% endfor %}
"""

t3 = BashOperator(
    task_id='templated',
    bash_command=templated_command,
    params={'my_param': 'Parameter I passed in'},
    dag=dag)

t2.set_upstream(t1)
t3.set_upstream(t1)

测试

运行脚本

是时候进行一些测试了。首先让我们确保管道解析。假设我们正在保存上一步中 tutorial.py引用的DAGs文件夹中的代码airflow.cfg。DAG的默认位置是~/airflow/dags

python ~/airflow/dags/tutorial.py

如果脚本没有引发异常,则意味着您没有做任何可怕的错误,并且您的Airflow环境有点健全。

命令行元数据验证

让我们运行一些命令来进一步验证这个脚本。

# print the list of active DAGs
airflow list_dags

# prints the list of tasks the "tutorial" dag_id
airflow list_tasks tutorial

# prints the hierarchy of tasks in the tutorial DAG
airflow list_tasks tutorial --tree

测试

让我们通过在特定日期运行实际任务实例来进行测试。在此上下文中指定的日期是a execution_date,它模拟在特定日期+时间运行任务或dag的调度程序:

# command layout: command subcommand dag_id task_id date

# testing print_date
airflow test tutorial print_date 2015-06-01

# testing sleep
airflow test tutorial sleep 2015-06-01

现在还记得我们之前用模板做过的事吗?通过运行此命令,了解如何呈现和执行此模板:

# testing templated
airflow test tutorial templated 2015-06-01

这应该导致显示详细的事件日志并最终运行bash命令并打印结果。

请注意,该命令在本地运行任务实例,将其日志输出到stdout(在屏幕上),不依赖于依赖项,并且不向数据库传达状态(运行,成功,失败,...)。它只允许测试单个任务实例。airflow test

回填

一切看起来都运行良好所以让我们运行回填。 backfill将尊重您的依赖项,将日志发送到文件并与数据库通信以记录状态。如果您有网络服务器,您将能够跟踪进度。如果您有兴趣在回填过程中直观地跟踪进度,则将启动Web服务器。airflow webserver

请注意,如果使用depends_on_past=True,则单个任务实例将取决于前面任务实例的成功,除了指定了自身的start_date,此依赖关系将被忽略。

此上下文中的日期范围是a start_date和可选的a end_date,用于使用此dag中的任务实例填充运行计划。

# optional, start a web server in debug mode in the background
# airflow webserver --debug &

# start your backfill on a date range
airflow backfill tutorial -s 2015-06-01 -e 2015-06-07

猜你喜欢

转载自blog.csdn.net/yizhuanlu9607/article/details/88943603