airflow 文档学习(二) - 概念

1. 核心功能

1.1 DAGs

有向无环图

反映所涉及的task的依赖关系

注:搜索dag的时候,airflow只会关注同事包含"DAG"和"airflow"字样的py文件

1.2 scope

airflow将加载任何可以从DAG file中import的DAG对象,但是它们必须出现在globals()中,例如下面的文件,只有tag_1会被加载,tag_2只会出现在本地scope中

dag_1 = DAG('this_dag_will_be_discovered')
def my_function():
dag_2 = DAG('but_this_dag_will_not')
my_function()

1.3 Default Arguments

如果一个字典default_args被传给一个DAGs,它将会将其运用到所有的它的operator中。这使得复用default_args变得非常的方便

1.4 Context Manager

dags可以被当做一个管理器,去自动的分配新的operators给dag

1.5 Operators

dags描述的是怎么去跑一个工作流,operators决定实际做什么。

一个operator描述了在一个工作流中的单个task。operators经常但不总是原子的,这意味着他们可以独立存在而不需要去和别的operator分享资源。DAG将确保operators以正确的顺序运行,在这些依赖之外,operator通常是独立运行的,甚至他们肯能运行在不同的机器上。

这是个非常微妙的关键点:事实上,如果两个operator需要去共享一些信息,就像文件名或者一些小的数据,你应该去考虑将他们合并到一个operator中,如果上述情况确实是无法避免的,airflow有operator的交叉通信(xcom)在文档中有描述。

并且airflow提供了非常多的通用operator:

BashOperator 
PythonOperator 
EmailOperator
SimpleHttpOperator 等等

1.6 DAG Assignment

operator不用立马被分配给一个dag,但是,一旦operator被分配给了一个dag,它将无法被转移或者是取消分配。dag的分配在operator被创建之后可以被非常明确的完成,通过延期分配或者从其他operator推断的方式

例如下面的方式:

dag = DAG('my_dag', start_date=datetime(2016, 1, 1))
# sets the DAG explicitly
explicit_op = DummyOperator(task_id='op1', dag=dag)
# deferred DAG assignment
deferred_op = DummyOperator(task_id='op2')
deferred_op.dag = dag
# inferred DAG assignment (linked operators must be in the same DAG)
inferred_op = DummyOperator(task_id='op3')
inferred_op.set_upstream(deferred_op)

1.7 Bitshift Composition

在以前,operator的关系描述是通过set_upstream()和set_downstream()方法,在1.8 之后可以通过<<和>>代替依赖方法。

1.8 Tasks

当一个operator被实例化之后,它就被称为是一个task。实例化在调用抽象operator时定义了具体的值,同时,参数化之后的task会称为dag的一个节点。

1.9 Task Instances

一个task实例代表一个task的特定运行,其特征在于dag、任务、和时间点的组合。

它拥有运行状态:running、success、failed、skipped、up for retry等

1.10 Workflows

通过组合dags和operators,你会创建TaskInstances,你可以创建复杂的工作流。

2. Additional Functionality

2.1 Hooks

Hooks是连接一些平台和数据库的接口,类似于 Hive, S3, MySQL, Postgres, HDFS, Pig。hooks尽可能的实现了通用接口,并且充当operator。还需要使用airflow.models.Connection 模型来检索主机名和身份认证信息,hooks将身份认证信息和代码放在管道之外,集中在元数据库中。

2.2 pools

一些系统会因为太多的进程不堪重负,airflow的pool可以被用作限制任意的task的运行。task可以在创建时通过参数指定存在的pool名称。

例如:

aggregate_db_message_job = BashOperator(
task_id='aggregate_db_message_job',
execution_timeout=timedelta(hours=3),
pool='ep_data_pipeline_db_msg_agg',
bash_command=aggregate_db_message_job_cmd,
dag=dag)
aggregate_db_message_job.set_upstream(wait_for_empty_queue)

pool中可以使用priority_weight参数去定义他的在队列中的权重,并且决定哪个task先行执行。

当容量被撑满时,task将会放入计划执行,一旦有容量,可运行的task和他们的状态将会被在前端展示,当插槽空闲,队列中的task将会基于权重进行排序执行。

2.3 Connections

外部系统的connection信息被存储在airflow的元数据库中,airflow的管道可以很简单地引用被集中管理的conn_id,无需另外进行操作。

当许多的connections被定义在同一个conn_id下,在这种情况下,当hooks使用get_connection方法时,airflow将随机选择一个connection,当重试时允许一些基本的负载均衡和容错。

一些hooks有默认的conn_id,当operators使用这个hook时不需要一个明确的conn_id。例如:PostgresHook的默认conn_id是postgres_default

2.4 Queues

当我们使用CeleryExecutor时,被塞入celery队列的task是可以被规定的,队列是BaseOperator的属性,所以任何task可以被分配到任何的队列中,而默认的队列环境是在配置文件的celery下的default_queue中配置的。

workers可以监听一个或多个队列中的task,当一个worker启动的时候(使用airflow worker命令),一个以逗号分隔的对列名可以被指定(airflow worker -q spark),这个worker将只会选择那些被连接到指定对列的task。

2.5 XComs

XComs使得tasks可以交换信息,允许更加细微的控制形式和分享状态。XComs原则上定义成key、value和timestamp,但是也可以跟踪一些属性,例如创建XCom的task/DAG。

XComs可以被pushed或者pulled,当一个task发送一个xcom,这个xcom是普遍可获得的。task可以被发送通过使用方法xcom_push(),此外,当一个task返回一个值时(不管是operators的execute()方法还是PythonOperators的python_callable方法),一个包含着返回值的xcom会自动发送。

tasks调用xcom_pull()去接受xcoms,可选择的根据key、task_ids、dag_id进行过滤。默认的,xcom_pull()在获得值时会根据keys自动筛选执行方法。

如果xcom_pull被传了一个task_id,则对应task最近一次的xcom值会被返回,如果一组task_ids传过去,会返回一组对应的xcom值

也可以直接在模板中获取xcom,例如:SELECT * FROM {{ task_instance.xcom_pull(task_ids='foo', key='table_name') }}

值得注意的是,xcom与variable非常相似,但它是专门用于任务之间的通信而不是全局设置

2.6 Variables

variables是一种传统的方式去存储和取回任意的内容或者是key-value形式的airflow的设置,它可以在前端界面、代码或者cli中进行增删改查的操作,当你定义管道代码,就可非常方便的使用,例如:

from airflow.models import Variable
foo = Variable.get("foo")
bar = Variable.get("bar", deserialize_json=True)

你可以使用variables在一个jinjia模板中:

echo {{ var.value.<variable_name> }}

2.7 Branching

有时候你需要你的工作流进行分支,或者是根据任意上游发生的条件走某条路。这其中一种实现方法就是使用BranchPythonOperator

BranchPythonOperator和PythonOperator十分相似,除了python会期望一个python_callable去返回一个task_id,返回的task_id跳过所有其他路径,python的返回函数的task_id必须直接引用BranchPythonOperator任务下游的任务。

注意,在BranchPythonOperator中使用depend_on_past = True下游的任务在逻辑上是不合理的,因为跳过状态总是导致依赖于过去成功的块任务。如果非要这样的话可以中间建立一个虚拟任务进行过度。

2.8 SubDAGs

2.9 SLAs

记录失败的过错的sla任务列表

2.10 Trigger Rules

虽然正常的工作流行为是在所有的直接上游任务成功之后触发的,但是airflow允许更为复杂的依赖项。

所有的operators有一个trigger_rule,用来定义生成的任务被触发的规则,trigger_rule的默认参数是all_success,以下为别的参数解释:

all_success: (default) 所有的父级任务成功
all_failed: 所有的父级任务失败,或者上游状态为失败
all_done: 所有的父级任务执行完成
one_failed: 至少一个失败,并且不会等待所有任务执行完成
one_success: 至少一个成功,并且不会等待所有任务执行完成
dummy: 依赖只是为了展示,随意触发

注意,这些可以与depends_on_past结合使用,当设置为true时,如果任务的先前计划未成功,则不会触发

2.11 Latest Run Only

标准工作流行为涉及为特定日期/时间范围内运行的一系列任务,但是,某些工作流执行的任务与运行时间无关,但是需要按计划运行,就像标准的cron作业一样,在这些情况下,暂停期间错过的回填运行作业会浪费cpu周期。

2.12 Zombies & Undeads

僵尸任务的特点是没有心跳(由工作定期发出)和数据库中的运行状态,当工作节点无法访问数据库的时候,airflow进程在外部被终止或者节点重启的时候,他们可能会发生。僵尸查杀由调度程序的进程定期执行。

undead进程的特点是存在进程和匹配的心跳,但是airflow不知道此任务在数据库中运行。这种不匹配通常在数据库状态发生改变的时候发生,最有可能是通过删除UI中的任务实例视图中的行,指示任务验证其作为心跳例程的一部分的状态,并在确定他们处于这种不死的状态时终止自身。

2.13 Cluster Policy

你本地airflow设置文件可以定义一个策略功能,该功能可以根据其他任务或DAG属性改变其任务属性。

2.14 Documentation & Notes

2.15 Jinja Templating

posted @ 2018-12-11 14:57  INVOKERrrrrrr~  阅读(4470)  评论(0编辑  收藏  举报