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

 

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