Airflow調度工具簡介和使用

Airflow是airbnb家的基於DAG(有向無環圖)的任務管理系統, 最簡單的理解就是一個高級版的crontab。它解決了crontab無法解決的任務依賴問題。

本文將介紹 Airflow 這一款優秀的調度工具。主要包括 Airflow 的服務構成、Airflow 的 Web 界面、DAG 配置、常用配置等。

一、什麼是 Airflow

Airflow 是 Airbnb 開源的一個用 Python 編寫的調度工具。於 2014 年啓動,2015 年春季開源,2016 年加入 Apache 軟件基金會的孵化計劃。

Airflow 通過 DAG 也即是有向非循環圖來定義整個工作流,因而具有非常強大的表達能力。

如上圖所示,一個工作流可以用一個 DAG 來表示,在 DAG 中將完整得記錄整個工作流中每個作業之間的依賴關係、條件分支等內容,並可以記錄運行狀態。通過 DAG,我們可以精準的得到各個作業之間的依賴關係。

二、相關概念

在進一步介紹 Airflow 之前,先介紹一些在 Airflow 中常見的名詞概念:

DAG(directed acyclic graph)

DAG 意爲有向無循環圖,在 Airflow 中則定義了整個完整的作業。同一個 DAG 中的所有 Task 擁有相同的調度時間。在Linux 的 crontab 和 windows 的任務計劃中,他們可以配置定時任務或間隔任務,但不能配置作業之前的依賴關係,但是airflow 中 DAG 就是管理作業依賴關係的。DAG 的英文 directed acyclic graphs 即有向無環圖,下圖 1 便是一個簡單的 DAG
在這裏插入圖片描述
在 airflow 中這種 DAG 是通過編寫 Python 代碼來實現的,DAG 的編寫非常簡單,官方提供了很多的例子,在安裝完成後,啓動 webserver 即可看到 DAG 樣例的源碼(其實定義了 DAG 對象的 python 程序),稍做修改即可成爲自己的 DAG 。上圖 1 中 DAG 中的依賴關係通過下述三行代碼即可完成:
在這裏插入圖片描述

Task

Task 爲 DAG 中具體的作業任務,它必須存在於某一個 DAG 之中。Task 在 DAG 中配置依賴關係,跨 DAG 的依賴是可行的,但是並不推薦。跨 DAG 依賴會導致 DAG 圖的直觀性降低,並給依賴管理帶來麻煩。

DAG Run

當一個 DAG 滿足它的調度時間,或者被外部觸發時,就會產生一個 DAG Run。可以理解爲由 DAG 實例化的實例。

Task Instance

當一個 Task 被調度啓動時,就會產生一個 Task Instance。可以理解爲由 Task 實例化的實例。

三、Airflow 的服務構成

在這裏插入圖片描述
一個正常運行的 Airflow 系統一般由以下幾個服務構成

WebServer—web服務器

Airflow 提供了一個可視化的 Web 界面。啓動 WebServer 後,就可以在 Web 界面上查看定義好的 DAG 並監控及改變運行狀況。也可以在 Web 界面中對一些變量進行配置。

Executor—執行器

執行器有 SequentialExecutor, LocalExecutor, CeleryExecutor

SequentialExecutor 爲順序執行器,默認使用 sqlite 作爲知識庫,由於 sqlite 數據庫的原因,任務之間不支持併發執行,常用於測試環境,無需要額外配置。
LocalExecutor 爲本執行器,不能使用 sqlite 作爲知識庫,可以使用 mysql,postgress,db2,oracle 等各種主流數據庫,任務之間支持併發執行,常用於生產環境,需要配置數據庫連接 url。
CeleryExecutor 爲 Celery 執行器,需要安裝 Celery ,Celery 是基於消息隊列的分佈式異步任務調度工具。需要額外啓動工作節點-worker。使用 CeleryExecutor 可將作業運行在遠程節點上

Worker—工作節點

當執行器爲 CeleryExecutor 時,需要開啓一個 worker。
一般來說我們用 Celery Worker 來執行具體的作業。Worker 可以部署在多臺機器上,並可以分別設置接收的隊列。當接收的隊列中有作業任務時,Worker 就會接收這個作業任務,並開始執行。Airflow 會自動在每個部署 Worker 的機器上同時部署一個 Serve Logs 服務,這樣我們就可以在 Web 界面上方便的瀏覽分散在不同機器上的作業日誌了。

Scheduler—調度器

整個 Airflow 的調度由 Scheduler 負責發起,每隔一段時間 Scheduler 就會檢查所有定義完成的 DAG 和定義在其中的作業,如果有符合運行條件的作業,Scheduler 就會發起相應的作業任務以供 Worker 接收。

Flower

Flower 提供了一個可視化界面以監控所有 Celery Worker 的運行狀況。這個服務並不是必要的。

四、Airflow 的 Web 界面

下面簡單介紹一下 Airflow 的 Web 操作界面,從而可以對 Airflow 有一個更直觀的瞭解。
啓動web任務管理需要執行airflow websever -D命令,默認端口是8080
http://主機IP:8080/admin/

1、DAG 列表

在這裏插入圖片描述
(1)左側 On/Off 按鈕控制 DAG 的運行狀態,Off 爲暫停狀態,On 爲運行狀態。
注意:所有 DAG 腳本初次部署完成時均爲 Off 狀態。

(2)若 DAG 名稱處於不可點擊狀態,可能爲 DAG 被刪除或未載入。若 DAG 未載入,可點擊右側刷新按鈕進行刷新。
注意:由於可以部署若干 WebServer,所以單次刷新可能無法刷新所有 WebServer 緩存,可以嘗試多次刷新。
(3)Schedule:調度時間
(4)Owner:dag擁有者
(5)Recent Tasks 會顯示最近一次 DAG Run(可以理解爲 DAG 的執行記錄)中 Task Instances(可以理解爲作業的執行記錄)的運行狀態,共有9個狀態:
這裏包含9個圓圈,每個圓圈代表task的執行狀態和次數

圈1 success:現實成功的task數,基本上就是該tag包含多少個task,這裏基本上就顯示幾。
圈2 running:正在運行的task數
圈3 failed:失敗的task數
圈4 unstream_failed:
圈5 skipped:跳過的task數
圈6 up_for_retry:執行失敗的task,重新執行的task數
圈7queued:隊列,等待執行的task數
圈8 :
圈9 scheduled:剛開始調度dag時,這一次執行總共調度了dag下面多少個task數,並且隨着task的執行成功,數值逐漸減少。

(6)Last Run 顯示最近一次的 execution date。
注意:execution date 並不是真實執行時間,具體細節在下文 DAG 配置中詳述。將鼠標移至 execution date 右側 info 標記上,會顯示 start date,start date 爲真實運行時間。start date 一般爲 execution date 所對應的下次執行時間。
(7)DAG Runs
這裏顯示dag的執行信息,包括3個圓圈,每個圓圈代表dag的執行狀態和次數

圈1 success:總共執行成功的dag數,執行次數
圈2 runing:正在執行dag數
圈3 faild:執行失敗的dag數

(8)Links

Trigger Dag 人爲執行觸發
Tree View 當dag執行的時候,可以點入,查看每個task的執行狀態(基於樹狀視圖),狀態:success,running,failed,skipped,retry,queued,no status
Graph View 同上,基於圖視圖(有向無環圖),查看每個task的執行狀態,狀態:success,running,failed,skipped,retry,queued,no status
Tasks Duration 每個task的執行時間統計,可以選擇最近多少次執行(number of runs)
TaskTries 每個task的重試次數 Landing Times
Gantt View 基於甘特圖的視圖,每個task的執行狀態
Code View 查看任務執行代碼 Logs 查看執行日誌,比如失敗原因
Refresh 刷新dag任務
Delete Dag 刪除該dag任務 當某dag執行失敗,可以通過3個View視圖去查看是哪個task執行失敗。

2、作業操作框

在 DAG 的樹狀圖和 DAG 圖中都可以點擊對應的 Task Instance 以彈出 Task Instance 模態框,以進行 Task Instance 的相關操作。注意:選擇的 Task Instance 爲對應 DAG Run 中的 Task Instance。
在這裏插入圖片描述
(1)在作業名字的右邊有一個漏斗符號,點擊後整個 DAG 的界面將只顯示該作業及該作業的依賴作業。當該作業所處的 DAG 較大時,此功能有較大的幫助。

Task Instance Details 顯示該 Task Instance 的詳情,可以從中得知該 Task Instance 的當前狀態,以及處於當前狀態的原因。例如,若該 Task Instance 爲 no status 狀態,遲遲不進入 queued 及 running 狀態,此時就可通過 Task Instance Details 中的 Dependency 及 Reason 得知原因。

Rendered 顯示該 Task Instance 被渲染後的命令。

Run 指令可以直接執行當前作業。

Clear 指令爲清除當前 Task Instance 狀態,清除任意一個 Task Instance 都會使當前 DAG Run 的狀態變更爲 running。注意:如果被清除的 Task Instance 的狀態爲 running,則會嘗試 kill 該 Task Instance 所執行指令,並進入 shutdown 狀態,並在 kill 完成後將此次執行標記爲 failed(如果 retry 次數沒有用完,將標記爲 up_for_retry)。Clear 有額外的5個選項,均爲多選,這些選項從左到右依次爲:

Past: 同時清除所有過去的 DAG Run 中此 Task Instance 所對應的 Task Instance。
Future: 同時清除所有未來的 DAG Run 中此 Task Instance 所對應的 Task Instance。注意:僅清除已生成的 DAG Run 中的 Task Instance。
Upstream: 同時清除該 DAG Run 中所有此 Task Instance 上游的 Task Instance。
Downstream: 同時清除該 DAG Run 中所有此 Task Instance 下游的 Task Instance。
Recursive: 當此 Task Instance 爲 sub DAG 時,循環清除所有該 sub DAG 中的 Task Instance。注意:若當此 Task Instance 不是 sub DAG 則忽略此選項。
Mark Success 指令爲講當前 Task Instance 狀態標記爲 success。注意:如果該 Task Instance 的狀態爲 running,則會嘗試 kill 該 Task Instance 所執行指令,並進入 shutdown 狀態,並在 kill 完成後將此次執行標記爲 failed(如果 retry 次數沒有用完,將標記爲 up_for_retry)。

3.Data Profiling 數據分析

在這裏插入圖片描述
(1)Ad Hoc Query:特殊查詢
通過UI界面對一些數據庫,數據倉庫的進行簡單的SQL交互操作.
在這裏插入圖片描述
在這裏插入圖片描述
(2)Charts:圖表
實現數據可視化和圖表的工作。通過SQL去源數據庫檢索一些數據,保存下來,供後續使用。
(3)Known Events:已知的事件

4.Browse 瀏覽

在這裏插入圖片描述
(1)SLA Misses

(2)Task Instances:查看每個task實例執行情況
在這裏插入圖片描述
Logs:查看所有dag下面對應的task的日誌,並且包含檢索
在這裏插入圖片描述
Jobs:查看dag的執行狀態,開始時間和結束時間等指標
在這裏插入圖片描述

5.Admin:管理員

在這裏插入圖片描述
Pools:

Configuration:查看airflow的配置,即:./airflow_home/airflow.cfg

**Users:**查看用戶列表,創建用戶,刪除用戶

Connections
我們的Task需要通過Hook訪問其他資源, Hook僅僅是一種訪問方式, 就像是JDBC driver一樣, 要連接DB, 我們還需要DB的IP/Port/User/Pwd等信息. 這些信息不太適合hard code在每個task中, 可以把它們定義成Connection, airflow將這些connection信息存放在後臺的connection表中. 我們可以在WebUI的Admin->Connections管理這些連接.

Variables
Variable 沒有task_id/dag_id屬性, 往往用來定義一些系統級的常量或變量, 我們可以在WebUI或代碼中新建/更新/刪除Variable. 也可以在WebUI上維護變量.
Variable 的另一個重要的用途是, 我們爲Prod/Dev環境做不同的設置, 詳見後面的開發小節.

XComs
XCom和Variable類似, 用於Task之間共享一些信息. XCom 包含task_id/dag_id屬性, 適合於Task之間傳遞數據, XCom使用方法比Variables複雜些. 比如有一個dag, 兩個task組成(T1->T2), 可以在T1中使用xcom_push()來推送一個kv, 在T2中使用xcom_pull()來獲取這個kv.

6.Docs

在這裏插入圖片描述
(1)官方文檔
(2)Github地址

五、Dag提交-python配置任務

1.DAG 基本參數配置
default_args = {
    'owner': 'airflow',
    'depends_on_past': False,   # 是否依賴上一個自己的執行狀態 
    'start_date': datetime.datetime(2019, 1, 1),
    'email': ['[email protected]'], # 需要在airflow.cfg中配置下發件郵箱
    'email_on_failure': False,
    'email_on_retry': False,
    'retries': 1,
    'retry_delay': datetime.timedelta(minutes=5),
    # 'end_date': datetime(2020, 1, 1),   # 結束時間,註釋掉也就會一直執行下去
}
2.DAG對象

設置dag的執行週期:schedule_interval.該參數可以接收cron 表達式和datetime.timedelta對象,另外airflow還預置了一些調度週期。
在這裏插入圖片描述

dag = DAG(
    'tutorial', 
default_args=default_args, 
schedule_interval='* * * * *' # 執行週期,crontab形式
)
3.定義任務

在定義這個任務的過程,就像是在寫一個 shell 腳本,只是這個腳本的每個操作可以有依賴。 不同的操作對應了不同的 Operator,比如 shell 就需要用 BashOperator 來執行。

t1 = BashOperator(   #任務類型是bash
    task_id='echoDate', #任務id
    bash_command='echo date > /home/datefile', #任務命令
    dag=dag)
4.完整樣例
# coding: utf-8

from airflow import DAG
from airflow.operators.python_operator import PythonOperator
from datetime import datetime, timedelta



# 定義默認參數
default_args = {
    'owner': 'wangzhenjun',  # 擁有者名稱
    'depends_on_past': False,   # 是否依賴上一個自己的執行狀態
    'start_date': datetime(2019, 1, 15, 10, 00),  # 第一次開始執行的時間,爲格林威治時間,爲了方便測試,一般設置爲當前時間減去執行週期
    'email': ['[email protected]'],  # 接收通知的email列表
    'email_on_failure': True,  # 是否在任務執行失敗時接收郵件
    'email_on_retry': True,  # 是否在任務重試時接收郵件
    'retries': 3,  # 失敗重試次數
    'retry_delay': timedelta(seconds=5)  # 失敗重試間隔
}

# 定義DAG
dag = DAG(
    dag_id='hello_world',  # dag_id
    default_args=default_args,  # 指定默認參數
    # schedule_interval="00, *, *, *, *" 
     # 執行週期,依次是分,時,天,月,年,此處表示每個整點執行
    schedule_interval=timedelta(minutes=1)  # 執行週期,表示每分鐘執行一次
)

"""
1.通過PythonOperator定義執行python函數的任務
"""
# 定義要執行的Python函數1
def hello_world_1():
    current_time = str(datetime.today())
    with open('/root/tmp/hello_world_1.txt', 'a') as f:
        f.write('%s\n' % current_time)
    assert 1 == 1  # 可以在函數中使用assert斷言來判斷執行是否正常,也可以直接拋出異常
# 定義要執行的Python函數2
def hello_world_2():
    current_time = str(datetime.today())
    with open('/root/tmp/hello_world_2.txt', 'a') as f:
        f.write('%s\n' % current_time)

# 定義要執行的task 1
t1 = PythonOperator(
    task_id='hello_world_1',  # task_id
    python_callable=hello_world_1,  # 指定要執行的函數
    dag=dag,  # 指定歸屬的dag
    retries=2,  # 重寫失敗重試次數,如果不寫,則默認使用dag類中指定的default_args中的設置
)
# 定義要執行的task 2
t2 = PythonOperator(
    task_id='hello_world_2',  # task_id
    python_callable=hello_world_2,  # 指定要執行的函數
    dag=dag,  # 指定歸屬的dag
)

 # t2依賴於t1;等價於 t1.set_downstream(t2);
 #同時等價於 dag.set_dependency('hello_world_1', 'hello_world_2')
t2.set_upstream(t1) 
# 表示t2這個任務只有在t1這個任務執行成功時才執行,
# 或者
t1 >> t2


"""
2.通過BashOperator定義執行bash命令的任務
"""
hello_operator = BashOperator(   #通過BashOperator定義執行bash命令的任務
    task_id='sleep_task',
    depends_on_past=False,
    bash_command='echo `date` >> /home/py/test.txt',
    dag=dag
)
"""
其他任務處理器:
3.EmailOperator : 發送郵件
4.HTTPOperator : 發送 HTTP 請求
5.SqlOperator : 執行 SQL 命令
"""

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章