大数据调度系统AirFlow全知全解+使用案例篇

1、What Is AirFLow

Apache Airflow提供基于DAG有向无环图来编排工作流的、可视化的分布式任务调度,与Oozie、Azkaban等任务流调度平台类似。采用Python语言编写,提供可编程方式定义DAG工作流,可以定义一组有依赖的任务,按照依赖依次执行, 实现任务管理、调度、监控功能。此外提供WebUI可视化界面,提供了工作流节点的运行监控,查看每个节点的运行状态、运行耗时、执行日志等。
在这里插入图片描述
● 处理数据ETL任务( 源->端 处理过程与管理)
● 依赖需求

What Is Dependecy
● 时间依赖:任务需要等待某一个时间点触发
● 外部系统依赖:任务依赖Mysql中的数据,HDFS中的数据等等,这些不同的外部系统需要调用接口去访问
● 机器依赖:任务的执行只能在特定的某一台机器的环境中,可能这台机器内存比较大,也可能只有那台机器上有特殊的库文件
● 任务间依赖:任务A需要在任务B完成后启动,两个任务互相间会产生影响
● 资源依赖:任务消耗资源非常多,使用同一个资源的任务需要被限制,比如跑个数据转换任务要10个G,机器一共就30个G,最多只能跑两个,我们希望类似的任务排个队
● 权限依赖:某种任务只能由某个权限的用户启动

1.1 Architecture Overview

AirFlow

在这里插入图片描述

1. webserver

提供web端服务,以及会定时生成子进程去扫描对应的目录下的dags,并更新数据库
webserver 提供以下功能:
● 中止、恢复、触发任务。
● 监控正在运行的任务,断点续跑任务。
● 执行 ad-hoc 命令或 SQL 语句来查询任务的状态,日志等详细信息。
● 配置连接,包括不限于数据库、ssh 的连接等。

webserver 守护进程使用 gunicorn 服务器(相当于 java 中的 tomcat )处理并发请求,可通过修改{AIRFLOW_HOME}/airflow.cfg文件中 workers 的值来控制处理并发请求的进程数。
例如:workers = 4 #表示开启4个gunicorn worker(进程)处理web请求

2. scheduler

任务调度服务,周期性地轮询任务的调度计划,以确定是否触发任务执行,根据dags生成任务,并提交到消息中间件队列中 (redis或rabbitMq)

3. worker

分布在不同的机器上,作为任务真正的的执行节点。通过监听消息中间件: redis或rabbitMq 领取任务
当设置 airflow 的 executors 设置为 CeleryExecutor 时才需要开启 worker 守护进程。推荐你在生产环境使用 CeleryExecutor :

executor = CeleryExecutor
4. flower

监控worker进程的存活性,启动或关闭worker进程,查看运行的task
默认的端口为 5555,您可以在浏览器地址栏中输入 “ http://localhost:5555” 来访问 flower ,对 celery 消息队列进行监控。

Celery

Celery 主要角色:
在这里插入图片描述
Celery 任务流程:
在这里插入图片描述

Celery 深入了解可参考如下:
1 celery 文档 http://docs.celeryproject.org/en/latest/getting-started/first-steps-with-celery.html
2 project layout http://docs.celeryproject.org/en/latest/getting-started/next-steps.html#project-layout
2-1 celery 的 配置介绍 http://docs.celeryproject.org/en/latest/userguide/configuration.html#configuration
3 可以设置任务的类型 http://docs.jinkan.org/docs/celery/_modules/celery/app/task.html#Task.apply_async
4 kombu Messaging library for Python https://kombu.readthedocs.io/en/stable/
4-1 kombu github 地址 https://github.com/celery/kombu
4-2 komub producer https://kombu.readthedocs.io/en/stable/userguide/producers.html
5 Celery 最佳实践(转) https://rookiefly.cn/detail/229
6 celery community http://www.celeryproject.org/community/
7 celery 通过 task_id 拿到任务的状态 http://docs.celeryproject.org/en/master/faq.html#how-do-i-get-the-result-of-a-task-if-i-have-the-id-that-points-there
8 python celery 任务队列 https://www.pyfdtic.com/2018/03/16/python-celery-%E4%BB%BB%E5%8A%A1%E9%98%9F%E5%88%97/
9 worker 相关 http://docs.celeryproject.org/en/latest/userguide/workers.html
10 Celery 简介 http://docs.jinkan.org/docs/celery/getting-started/introduction.html

1.2 Base Concepts

https://airflow.apache.org/docs/apache-airflow/stable/concepts/index.html

● Data Pipeline:数据管道或者数据流水线,可以理解为贯穿数据处理分析过程中不同工作环节的流程,例如加载不同的数据源,数据加工以及可视化。
● DAGs:是有向非循环图(directed acyclic graphs),可以理解为有先后顺序任务的多个Tasks的组合。图的概念是由节点组成的,有向的意思就是说节点之间是有方向的,转成工业术语我们可以说节点之间有依赖关系;非循环的意思就是说节点直接的依赖关系只能是单向的,不能出现 A 依赖于 B,B 依赖于 C,然后 C 又反过来依赖于 A 这样的循环依赖关系。每个 Dag 都有唯一的 DagId,当一个 DAG 启动的时候,Airflow 都将在数据库中创建一个DagRun记录,相当于一个日志。
● Task:是包含一个具体Operator的对象,operator实例化的时候称为task。DAG图中的每个节点都是一个任务,可以是一条命令行(BashOperator),也可以是一段 Python 脚本(PythonOperator)等,然后这些节点根据依赖关系构成了一个图,称为一个 DAG。当一个任务执行的时候,实际上是创建了一个 Task实例运行,它运行在 DagRun 的上下文中。
● Connections(Hooks):是管理外部系统的连接对象,如外部MySQL、HTTP服务等,连接信息包括conn_id/hostname/login/password/schema等,可以通过界面查看和管理,编排workflow时,使用conn_id进行使用。
● Pools: 用来控制tasks执行的并行数。将一个task赋给一个指定的pool,并且指明priority_weight权重,从而干涉tasks的执行顺序。
● XComs:在airflow中,operator一般是原子的,也就是它们一般是独立执行,不需要和其他operator共享信息。但是如果两个operators需要共享信息,例如filename之类的,则推荐将这两个operators组合成一个operator;如果一定要在不同的operator实现,则使用XComs (cross-communication)来实现在不同tasks之间交换信息。在airflow 2.0以后,因为task的函数跟python常规函数的写法一样,operator之间可以传递参数,但本质上还是使用XComs,只是不需要在语法上具体写XCom的相关代码。
● Trigger Rules:指task的触发条件。默认情况下是task的直接上游执行成功后开始执行,airflow允许更复杂的依赖设置,包括all_success(所有的父节点执行成功),all_failed(所有父节点处于failed或upstream_failed状态),all_done(所有父节点执行完成),one_failed(一旦有一个父节点执行失败就触发,不必等所有父节点执行完成),one_success(一旦有一个父节点执行成功就触发,不必等所有父节点执行完成),dummy(依赖关系只是用来查看的,可以任意触发)。另外,airflow提供了depends_on_past,设置为True时,只有上一次调度成功了,才可以触发。
● Backfill: 可以支持重跑历史任务,例如当ETL代码修改后,把上周或者上个月的数据处理任务重新跑一遍。
● Airflow 2.0 API,是一种通过修饰函数,方便对图和任务进行定义的编码方式,主要差别是2.0以后前一个任务函数作为后一个任务函数的参数,通过这种方式来定义不同任务之间的依赖关系。
● AIRFLOW_HOME 是 Airflow 寻找 DAG 和插件的基准目录。当数据工程师开发完python脚本后,需要以DAG模板的方式来定义任务流,然后把dag文件放到AIRFLOW_HOME下的DAG目录,就可以加载到airflow里开始运行该任务。

1.2.1 Operator

官方: While DAGs describe how to run a workflow, Operators determine what actually gets done by a task.

业务 —> 需求 ----> 作业(DAG/JOB) ---->一系列的任务(数据提取[可复用], 数据清洗[可复用], 数据转换[可复用], 数据聚合/分析[可复用], 目标指标/标签加工) + 通信/运维任务

在这里插入图片描述
● BashOperator (父类)
● XComs
● Sensor
● 自定义Operator

Sensor

注意现在支持3种模式了:
在这里插入图片描述

1.7 Version Operator

在这里插入图片描述

2.X Version Operator

在这里插入图片描述

1.2.2 Executor

执行器是任务实例运行的机制。
Airflow 支持各种Executor。当前使用的模式由配置文件 [core] 部分中的 executor 选项确定。此选项应包含名称 executor,例如KubernetesExecutor 如果它是核心执行器。如果要加载您自己的执行程序,那么您应该指定模块的完整路径,例如my_acme_company.executors.MyCustomExecutor。

# The executor class that airflow should use. Choices include
# ``SequentialExecutor``, ``LocalExecutor``, ``CeleryExecutor``, ``DaskExecutor``,
# ``KubernetesExecutor``, ``CeleryKubernetesExecutor`` or the
# full import path to the class when using a custom executor.
executor = LocalExecutor

可以通过以下命令查看当前设置的模式

airflow config get-value core executor

Supported Backends:
● Sequential Executor
● Debug Executor
● Local Executor
● Dask Executor
● Celery Executor
● Kubernetes Executor
● CeleryKubernetes Executor

接下来讲下常用的两种模式:

1. CeleryExecutor 模式
    CeleryExecutor是一种易于水平扩展的Executor,基于Celery实现。Celery本身是一个Python分布式队列组件,对于调度性能,LoadBalance,服务的稳定性,扩展性都能带来较大的提升, 但部署稍微麻烦点.

在这里插入图片描述
在这里插入图片描述

2. Local Executor

– TODO 这种方式我还得再验证下
在这里插入图片描述
在Airflow中使用LocalExecutor是比较典型的单节点部署架构,Scheduler和所有执行Task的代码都运行在同一个节点上(比如现在生产上的 hadoopslave81; hadoopslave82 )。Airflow Worker以LocalWorker的形式并发运行Scheduler分发的task。
在使用LocalExecutor的情况下,我们不需要该节点外的其他资源即可运行DAG。LocalExecutor将所有工作负载都会运行在一个节点上。部署虽然简单但扩展能差,特别是在大量任务的时候不好进行LoadBanlance

LocalExecutor虽然部署简单,生产环境建议还是采用CeleryExecutor部署模式

2. New Features(2.x)

Airflow 2.0是一个主要的版本(超级大的版本更新),不仅仅 UI 更新了,最核心的组件 Scheduler 性能也有了极大的提升,分布式环境下的高可用模型也做了改变,同时还有 Airflow 上的 Operator 和 Hook 也做了新的分门别类

2.1 TaskFlow API

引入了编写DAG的新方法: TaskFlow API 一种新的编写dags的方式
DAGs现在更容易进行编写,特别是在使用到PythonOperator的时候.任务之间的依赖更清楚,XCom更加的好用.
eg:

from airflow.decorators import dag, task
from airflow.utils.dates import days_ago

@dag(default_args={'owner': 'airflow'}, schedule_interval=None, start_date=days_ago(2))
def tutorial_taskflow_api_etl():
   @task
   def extract():
       return {"1001": 301.27, "1002": 433.21, "1003": 502.22}

   @task
   def transform(order_data_dict: dict) -> dict:
       total_order_value = 0

       for value in order_data_dict.values():
           total_order_value += value

       return {"total_order_value": total_order_value}

   @task()
   def load(total_order_value: float):

       print("Total order value is: %.2f" % total_order_value)

   order_data = extract()
   order_summary = transform(order_data)
   load(order_summary["total_order_value"])

tutorial_etl_dag = tutorial_taskflow_api_etl()

2.2 UI

崭新的用户界面(Refreshed UI)
我们已经给 Airflow UI a visual refresh 并更新了一些样式.

2.3 Scheduler性能提升

在这里插入图片描述

之前 Scheduler 的分布式执行是使用主从模型,但是在 Airflow 2.0 改成了主主模型,我的理解是就是基于元数据库,所有的 Scheduler 都是对等的。带来的优势就是:
● 之前崩溃的调度程序的恢复时间主要依赖于外部健康检查第一时间发现识别故障,但是现在停机时间为零且没有恢复时间,因为其他主动调度程序会不断运行并接管操作。
● 支持读单个调度程序进行更改,而不会影响其他调度程序。

对于某个单 Scheduler 来说,1.7 就引入了 DAG 序列化,通过使 Web 服务器无需解析 DAG 文件而允许它读取序列化的DAG,大大提高了 DAG 文件的读取性能。Airflow 2.0 Scheduler 通过使用来自数据库的序列化后 DAG 进行任务调度和调用,扩展了 DAG 序列化的使用。这减少了重复解析 DAG 文件以进行调度所需的时间。
官方压测结果

官方提供的一份性能对比图,如下:
benchmarking configuration was: 4 Celery Workers, PostgreSQL DB, 1 Web Server, 1 Scheduler.
Results for 1,000 tasks run, measured as total task latency (referenced below as task lag).

在这里插入图片描述
吞吐量是随着schedulers线性增长的

在这里插入图片描述

2.4 Task Groups

SubDAGs were commonly used for grouping tasks in the UI, but they had many drawbacks in their execution behaviour (primarily that they only executed a single task in parallel!) To improve this experience, we’ve introduced “Task Groups”: a method for organizing tasks which provides the same grouping behaviour as a subdag without any of the execution-time drawbacks.
SubDAGs will still work for now, but we think that any previous use of SubDAGs can now be replaced with task groups. If you find an example where this isn’t the case, please let us know by opening an issue on GitHub
For more information, check out the Task Group documentation.

SubDAG 通常用于在 UI 中对任务进行分组,但它们的执行行为有许多缺点(主要是它们只能并行执行单个任务!)为了改善这种体验,我们引入了“TaskGroup”:一种用于组织任务提供与 subdag 相同的分组行为,而没有任何执行时间缺陷。

2.5 更智能的Sensors

传感器(sensors)非常棘手,因为它们一直在寻找状态,并且可能会消耗大量资源。在新版本中,Airflow引入了对传感器逻辑的更改,以使其更加节省资源和更智能。就个人而言,我倾向于使用事件驱动的AWS Lambda函数处理用例,这些用例通常在Airflow中通过传感器使用(例如,当特定文件到达S3后立即触发管道)。但是,此功能对于许多希望将所有工作流程保持在一个地方而不是依赖于FaaS进行事件驱动的人来说非常有用。

2.6 安全性

作为 Airflow 2.0 努力的一部分,有意识地关注安全性和减少暴露区域. 这在不同的功能领域以不同的形式表现出来. 例如,在新的 REST API 中,所有操作现在都需要授权.同样,在配置设置中,现在需要指定 Fernet 密钥.
1.7版本安全仅支持kerberos

在这里插入图片描述
2.0版本已支持用户权限控制了
在这里插入图片描述
可惜还是不支持多租户隔离…

2.7 配置

airflow.cfg 文件形式的配置在不同的部分得到了进一步的合理化,特别是围绕“core”模块.此外,大量配置选项已被弃用或移至各个特定于组件的配置文件,例如用于 Kubernetes 执行相关配置的 pod-template-file.

2.8 REST API

完全可用的REST API(AIP-32)
我们现在有一个完全可用的,不再是实验性的 API 和一个全面的 OpenAPI 规范.
文档的REST API提供了两套在线文档,可以在界面进行交互的Swagger和静态的Redoc,对需要使用Airflow REST API的用户非常友好.

在这里插入图片描述

3. How To Use

https://airflow.apache.org/docs/apache-airflow/stable/_api/airflow/models/baseoperator/index.html#module-airflow.models.baseoperator%E3%80%82

3.1 USE STEP

在这里插入图片描述

3.2 USE CASE

BaseOperator中常用参数

  • task_id(str) : 唯一task_id标记
  • owner(str):任务的所有者,建议使用linux用户名
  • email(str or list[str]):出问题时,发送报警Email的地址,可以填写多个,用逗号隔开。
  • email_on_retry(bool):当任务重试时是否发送电子邮件
  • email_on_failure(bool):当任务执行失败时是否发送电子邮件
  • retries(int):在任务失败之前应该重试的次数
    retry_delay(datetime.timedelta)**:重试间隔,必须是timedelta对象
  • start_date(datetime.datetime)**:DAG开始执行时间,这个参数必须是datetime对象,不可以使用字符串。
  • end_date(datetime.datetime):DAG运行结束时间,任务启动后一般都会一直执行下去,一般不设置此参数。
  • depends_on_past(bool,默认False):是否依赖于过去,如果为True,那么必须之前的DAG调度成功了,现在的DAG调度才能执行。
  • **dag(airflow.models.DAG):指定的dag。
  • execution_timeout(datetime.timedelta):执行此任务实例允许的最长时间,超过最长时间则任务失败。
  • trigger_rule(str):定义依赖的触发规则,包括选项如下:{ all_success | all_failed | all_done | one_success | one_failed | none_failed | none_failed_or_skipped | none_skipped | dummy(无条件执行)} default is all_success。

一、BashOperator及调度Shell命令及脚本

bash_command(str):要执行的命令或脚本(脚本必须是.sh结尾)
1.1 BashOperator及调度Shell命令及脚本

BashOperator主要执行bash脚本或命令,BashOperator参数如下:

BashOperator 调度Shell命令案例

from datetime import datetime, timedelta

from airflow import DAG
from airflow.operators.bash import BashOperator

default_args = {
    'owner':'zhangsan',
    'start_date':datetime(2022, 7, 19),
    'email':'xxxx@163.com', 
    'retries': 1,  # 失败重试次数
    'retry_delay': timedelta(minutes=5) # 失败重试间隔
}

dag = DAG(
    dag_id = 'execute_shell_cmd',
    default_args=default_args,
    schedule_interval=timedelta(minutes=1)
)

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

t2=BashOperator(
    task_id='print_helloworld',
    bash_command='echo "hello world!"',
    dag=dag
)

t3=BashOperator(
    task_id='tempplated',
    bash_command="""
    {% for i in range(5) %}
        echo "{{ ds }}"
        echo "{{ params.name}}"
        echo "{{ params.age}}"
    {% endfor %}
    """,
    params={'name':'wangwu','age':10},
    dag=dag
)

t1 >> t2 >> t3

注意在t3中使用了Jinja模板,“{% %}”内部是for标签,用于循环操作,但是必须以{% endfor %}结束。“{{}}”内部是变量,其中ds是执行日期,是airflow的宏变量,params.name和params.age是自定义变量。
在default_args中的email是指当DAG执行失败时,发送邮件到指定邮箱,想要使用airflow发送邮件,需要在$AIRFLOW_HOME/airflow.cfg中配置如下内容:

[smtp]
# If you want airflow to send emails on retries, failure, and you want to use
# the airflow.utils.email.send_email_smtp function, you have to configure an
# smtp server here
smtp_host = smtp.163.com
smtp_starttls = True
smtp_ssl = False
# Example: smtp_user = airflow
smtp_user =xxxxxx
# Example: smtp_password = airflow
smtp_password =xxxxx
smtp_port = 25
smtp_mail_from =pudi@163.com
smtp_timeout = 30
smtp_retry_limit = 5
1.2 BashOperator 调度Shell脚本案例

准备如下两个shell脚本,将以下两个脚本放在$AIRFLOW_HOME/dags目录下,
BashOperator默认执行脚本时,默认从/tmp/airflow**临时目录查找对应脚本,由于临时目录名称不定,这里建议执行脚本时,在“bash_command”中写上绝对路径。如果要写相对路径,可以将脚本放在/tmp目录下,在“bash_command”中执行命令写上“sh …/xxx.sh”也可以。

first_shell.sh

#!/bin/bash

dt=$1

echo "==== execute first shell ===="

echo "---- first : time is ${dt}"

second_shell.sh

#!/bin/bash
dt=$1
echo "==== execute second shell ===="
echo "---- second : time is ${dt}"

编写airflow python 配置:

from datetime import datetime, timedelta
from airflow import DAG
from airflow.operators.bash import BashOperator

default_args = {
    'owner':'zhangsan',
    'start_date':datetime(2021, 9, 23),
    'retries': 1,  # 失败重试次数
    'retry_delay': timedelta(minutes=5) # 失败重试间隔
}

dag = DAG(
    dag_id = 'execute_shell_sh',
    default_args=default_args,
    schedule_interval=timedelta(minutes=1)
)

first=BashOperator(
    task_id='first',
    #脚本路径建议写绝对路径
    bash_command='sh /root/airflow/dags/first_shell.sh %s'%datetime.now().strftime("%Y-%m-%d"),
    dag = dag
)

second=BashOperator(
    task_id='second',
    #脚本路径建议写绝对路径
    bash_command='sh /root/airflow/dags/second_shell.sh %s'%datetime.now().strftime("%Y-%m-%d"),
    dag=dag
)

first >> second

在这里插入图片描述
在这里插入图片描述

特别注意:在“bash_command”中写执行脚本时,一定要在脚本后跟上空格,有没有参数都要跟上空格,否则会找不到对应的脚本。如下:

在这里插入图片描述

在这里插入图片描述

二、HiveOperator及调度HQL

可以通过HiveOperator直接操作Hive SQL ,HiveOperator的参数如下:

hql(str):需要执行的Hive SQL。
hive_cli_conn_id(str):连接Hive的conn_id,在airflow webui connection中配置的。

想要在airflow中使用HiveOperator调用Hive任务,首先需要安装以下依赖并配置Hive Metastore:

#切换Python37环境
[root@node4 ~]# conda activate python37

#安装hive provider package
(python37) [root@node4 ~]# pip install apache-airflow-providers-apache-hive==2.0.2

#启动airflow
(python37) [root@node4 ~]# airflow webserver --port 8080
(python37) [root@node4 ~]# airflow scheduler

登录Airflow webui并设置Hive Metastore,登录后找到”Admin”->”Connections”,点击“+”新增配置:
在这里插入图片描述

2.1 HiveOperator调度HQL案例

1、启动Hive,准备表
启动HDFS、Hive Metastore,在Hive中创建以下两张表:

create table person_info(id int,name string,age int) row format delimited fields terminated by '\t';

create table score_info(id int,name string,score int) row format delimited fields terminated by '\t';

向表 person_info加载如下数据:
1 zs 18
2 ls 19
3 ww 20
向表score_info加载如下数据:
1 zs 100
2 ls 200
3 ww 300

2、在node4节点配置Hive 客户端
由于Airflow 使用HiveOperator时需要在Airflow安装节点上有Hive客户端,所以需要在node4节点上配置Hive客户端。
将Hive安装包上传至node4 “/software”下解压,并配置Hive环境变量

#在/etc/profile文件最后配置Hive环境变量
export HIVE_HOME=/software/hive-1.2.1
export PATH=$PATH:$HIVE_HOME/bin

#使环境变量生效
source /etc/profile

修改HIVE_HOME/conf/hive-site.xml ,写入如下内容:

<configuration>
 <property>
  <name>hive.metastore.warehouse.dir</name>
  <value>/user/hive/warehouse</value>
 </property>
 <property>
  <name>hive.metastore.local</name>
  <value>false</value>
 </property>
 <property>
  <name>hive.metastore.uris</name>
  <value>thrift://node1:9083</value>
 </property>
</configuration>

3、编写DAG python配置文件
注意在本地开发工具编写python配置时,需要用到HiveOperator,需要在本地对应的python环境中安装对应的provider package。

C:\Users\wubai>d:
D:\>cd d:\ProgramData\Anaconda3\envs\python37\Scripts
d:\ProgramData\Anaconda3\envs\python37\Scripts>pip install apache-airflow-providers-apache-hive==2.0.2
注意:这里本地安装也有可能缺少对应的C++环境,我们也可以不安装,直接跳过也可以。

Python配置文件:

from datetime import datetime, timedelta
from airflow import DAG
from airflow.providers.apache.hive.operators.hive import HiveOperator

default_args = {
    'owner':'wangwu',
    'start_date':datetime(2021, 9, 23),
    'retries': 1,  # 失败重试次数
    'retry_delay': timedelta(minutes=5) # 失败重试间隔
}

dag = DAG(
    dag_id = 'execute_hive_sql',
    default_args=default_args,
    schedule_interval=timedelta(minutes=1)
)

first=HiveOperator(
    task_id='person_info',
    hive_cli_conn_id="node1-hive-metastore",
    hql='select id,name,age from person_info',
    dag = dag
)

second=HiveOperator(
    task_id='score_info',
    hive_cli_conn_id="node1-hive-metastore",
    hql='select id,name,score from score_info',
    dag=dag
)

third=HiveOperator(
    task_id='join_info',
    hive_cli_conn_id="node1-hive-metastore",
    hql='select a.id,a.name,a.age,b.score from person_info a join score_info b on a.id = b.id',
    dag=dag
)

first >> second >>third

4、调度python配置脚本
将以上配置好的python文件上传至node4节点$AIRFLOW_HOME/dags下,重启Airflow websever与scheduler,登录webui,开启调度:
在这里插入图片描述
调度结果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、PythonOperator

PythonOperator可以调用Python函数,由于Python基本可以调用任何类型的任务,如果实在找不到合适的Operator,将任务转为Python函数,使用PythonOperator即可。
关于PythonOperator常用参数如下,更多参数可以查看官网:airflow.operators.python — Airflow Documentation

python_callable(python callable):调用的python函数
op_kwargs(dict):调用python函数对应的 **args 参数,dict格式,使用参照案例。
op_args(list):调用python函数对应的 *args 参数,多个封装到一个tuple中,list格式,使用参照案例。

3.1 PythonOperator调度案例
import random
from datetime import datetime, timedelta
from airflow import DAG
from airflow.operators.python import PythonOperator

# python中 *  关键字参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。
# python中 ** 关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
def print__hello1(*a,**b):
    print(a)
    print(b)
    print("hello airflow1")
# 返回的值只会打印到日志中
    return{"sss1":"xxx1"}

def print__hello2(random_base):
    print(random_base)
    print("hello airflow2")
# 返回的值只会打印到日志中
    return{"sss2":"xxx2"}

default_args = {
    'owner':'maliu',
    'start_date':datetime(2021, 10, 1),
    'retries': 1,  # 失败重试次数
    'retry_delay': timedelta(minutes=5) # 失败重试间隔
}

dag = DAG(
    dag_id = 'execute_pythoncode',
    default_args=default_args,
    schedule_interval=timedelta(minutes=1)
)

first=PythonOperator(
    task_id='first',
    #填写  print__hello1 方法时,不要加上“()”
    python_callable=print__hello1,
    # op_args 对应 print_hello1 方法中的a参数
    op_args=[1,2,3,"hello","world"],
    # op_kwargs 对应 print__hello1 方法中的b参数
    op_kwargs={"id":"1","name":"zs","age":18},
    dag = dag
)

second=PythonOperator(
    task_id='second',
    #填写  print__hello2 方法时,不要加上“()”
    python_callable=print__hello2,
    # random_base 参数对应 print_hello2 方法中参数“random_base”
    op_kwargs={"random_base":random.randint(0,9)},
    dag=dag
)

first >> second
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

"""Example DAG demonstrating the usage of the PythonOperator."""
import time
from pprint import pprint

from airflow import DAG
from airflow.operators.python import PythonOperator, PythonVirtualenvOperator
from airflow.utils.dates import days_ago

args = {
    'owner': 'airflow',
}

with DAG(
    dag_id='example_python_operator',
    default_args=args,
    schedule_interval=None,
    start_date=days_ago(2),
    tags=['example'],
) as dag:

    # [START howto_operator_python]
    def print_context(ds, **kwargs):
        """Print the Airflow context and ds variable from the context."""
        pprint(kwargs)
        print(ds)
        return 'Whatever you return gets printed in the logs'

    run_this = PythonOperator(
        task_id='print_the_context',
        python_callable=print_context,
    )
    # [END howto_operator_python]

    # [START howto_operator_python_kwargs]
    def my_sleeping_function(random_base):
        """This is a function that will run within the DAG execution"""
        time.sleep(random_base)

    # Generate 5 sleeping tasks, sleeping from 0.0 to 0.4 seconds respectively
    for i in range(5):
        task = PythonOperator(
            task_id='sleep_for_' + str(i),
            python_callable=my_sleeping_function,
            op_kwargs={'random_base': float(i) / 10},
        )

        run_this >> task
    # [END howto_operator_python_kwargs]

    # [START howto_operator_python_venv]
    def callable_virtualenv():
        """
        Example function that will be performed in a virtual environment.

        Importing at the module level ensures that it will not attempt to import the
        library before it is installed.
        """
        from time import sleep

        from colorama import Back, Fore, Style

        print(Fore.RED + 'some red text')
        print(Back.GREEN + 'and with a green background')
        print(Style.DIM + 'and in dim text')
        print(Style.RESET_ALL)
        for _ in range(10):
            print(Style.DIM + 'Please wait...', flush=True)
            sleep(10)
        print('Finished')

    virtualenv_task = PythonVirtualenvOperator(
        task_id="virtualenv_python",
        python_callable=callable_virtualenv,
        requirements=["colorama==0.4.0"],
        system_site_packages=False,
    )
    # [END howto_operator_python_venv]

四、Xcom 通信

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

"""Example DAG demonstrating the usage of XComs."""
from airflow import DAG
from airflow.operators.python import PythonOperator
from airflow.utils.dates import days_ago

value_1 = [1, 2, 3]
value_2 = {'a': 'b'}


def push(**kwargs):
    """Pushes an XCom without a specific target"""
    kwargs['ti'].xcom_push(key='value from pusher 1', value=value_1)


def push_by_returning(**kwargs):
    """Pushes an XCom without a specific target, just by returning it"""
    return value_2


def puller(**kwargs):
    """Pull all previously pushed XComs and check if the pushed values match the pulled values."""
    ti = kwargs['ti']

    # get value_1
    pulled_value_1 = ti.xcom_pull(key=None, task_ids='push')
    if pulled_value_1 != value_1:
        raise ValueError(f'The two values differ {pulled_value_1} and {value_1}')

    # get value_2
    pulled_value_2 = ti.xcom_pull(task_ids='push_by_returning')
    if pulled_value_2 != value_2:
        raise ValueError(f'The two values differ {pulled_value_2} and {value_2}')

    # get both value_1 and value_2
    pulled_value_1, pulled_value_2 = ti.xcom_pull(key=None, task_ids=['push', 'push_by_returning'])
    if pulled_value_1 != value_1:
        raise ValueError(f'The two values differ {pulled_value_1} and {value_1}')
    if pulled_value_2 != value_2:
        raise ValueError(f'The two values differ {pulled_value_2} and {value_2}')


with DAG(
    'example_xcom',
    schedule_interval="@once",
    start_date=days_ago(2),
    default_args={'owner': 'airflow'},
    tags=['example'],
) as dag:

    push1 = PythonOperator(
        task_id='push',
        python_callable=push,
    )

    push2 = PythonOperator(
        task_id='push_by_returning',
        python_callable=push_by_returning,
    )

    pull = PythonOperator(
        task_id='puller',
        python_callable=puller,
    )

    pull << [push1, push2]

五、自定义Operator

● hook
● execute

六、其他

hive 支持的hook(官方叫hook其实还是不准确,应该叫数据源插件更准确),可以基于这些hook,可以实现很多不能任务的Operator
在这里插入图片描述


TODO 待补充 externalOperator sensorOperator

评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Pushkin.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值