簡(jiǎn)介
airflow是airbnb家的基于DAG(有向無(wú)環(huán)圖)的任務(wù)管理系統(tǒng), 最簡(jiǎn)單的理解就是一個(gè)高級(jí)版的crontab。它解決了crontab無(wú)法解決的任務(wù)依賴問(wèn)題。
類(lèi)似產(chǎn)品比較
系統(tǒng) | 介紹 |
---|---|
Apache Oozie | 使用XML配置, Oozie任務(wù)的資源文件都必須存放在HDFS上. 配置不方便同時(shí)也只能用于Hadoop. |
Linkedin Azkaban | web界面尤其很贊, 使用java properties文件維護(hù)任務(wù)依賴關(guān)系, 任務(wù)資源文件需要打包成zip, 部署不是很方便. |
airflow | 具有自己的web任務(wù)管理界面,dag任務(wù)創(chuàng)建通過(guò)python代碼,可以保證其靈活性和適應(yīng)性 |
web界面使用介紹
DAGS
啟動(dòng)web任務(wù)管理需要執(zhí)行airflow websever -D
命令,默認(rèn)端口是8080
http://10.191.76.31:8080/admin/
- DAG
dag_id - Schedule
調(diào)度時(shí)間 - Owner
dag擁有者 - Recent Tasks
這里包含9個(gè)圓圈,每個(gè)圓圈代表task的執(zhí)行狀態(tài)和次數(shù)
圈1 success:現(xiàn)實(shí)成功的task數(shù),基本上就是該tag包含多少個(gè)task,這里基本上就顯示幾。
圈2 running:正在運(yùn)行的task數(shù)
圈3 failed:失敗的task數(shù)
圈4 unstream_failed:
圈5 skipped:跳過(guò)的task數(shù)
圈6 up_for_retry:執(zhí)行失敗的task,重新執(zhí)行的task數(shù)
圈7 queued:隊(duì)列,等待執(zhí)行的task數(shù)
圈8 :
圈9 scheduled:剛開(kāi)始調(diào)度dag時(shí),這一次執(zhí)行總共調(diào)度了dag下面多少個(gè)task數(shù),并且隨著task的執(zhí)行成功,數(shù)值逐漸減少。 - Last Run
dag最后執(zhí)行的時(shí)間點(diǎn) - DAG Runs
這里顯示dag的執(zhí)行信息,包括3個(gè)圓圈,每個(gè)圓圈代表dag的執(zhí)行狀態(tài)和次數(shù)
圈1 success:總共執(zhí)行成功的dag數(shù),執(zhí)行次數(shù)
圈2 runing:正在執(zhí)行dag數(shù)
圈3 faild:執(zhí)行失敗的dag數(shù) - Links
link | 說(shuō)明 |
---|---|
Trigger Dag | 人為執(zhí)行觸發(fā) |
Tree View | 當(dāng)dag執(zhí)行的時(shí)候,可以點(diǎn)入,查看每個(gè)task的執(zhí)行狀態(tài)(基于樹(shù)狀視圖),狀態(tài):success,running,failed,skipped,retry,queued,no status |
Graph View | 同上,基于圖視圖(有向無(wú)環(huán)圖),查看每個(gè)task的執(zhí)行狀態(tài),狀態(tài):success,running,failed,skipped,retry,queued,no status |
Tasks Duration | 每個(gè)task的執(zhí)行時(shí)間統(tǒng)計(jì),可以選擇最近多少次執(zhí)行(number of runs) |
Task Tries | 每個(gè)task的重試次數(shù) |
Landing Times | |
Gantt View | 基于甘特圖的視圖,每個(gè)task的執(zhí)行狀態(tài) |
- Code View
查看任務(wù)執(zhí)行代碼 - Logs
查看執(zhí)行日志,比如失敗原因 - Refresh
刷新dag任務(wù)
-Delete Dag
刪除該dag任務(wù)
當(dāng)某dag執(zhí)行失敗,可以通過(guò)3個(gè)View視圖去查看是哪個(gè)task執(zhí)行失敗。
Data Profiling 數(shù)據(jù)分析
-
Ad Hoc Query:特殊查詢
通過(guò)UI界面對(duì)一些數(shù)據(jù)庫(kù),數(shù)據(jù)倉(cāng)庫(kù)的進(jìn)行簡(jiǎn)單的SQL交互操作.
Ad Hoc Query
image.png Charts:圖表
實(shí)現(xiàn)數(shù)據(jù)可視化和圖表的工作。通過(guò)SQL去源數(shù)據(jù)庫(kù)檢索一些數(shù)據(jù),保存下來(lái),供后續(xù)使用。
These charts are basic, but they’re easy to create, modify and share
You can even use the same templating and macros available when writing airflow pipelines, parameterizing your queries and modifying parameters directly in the URL.
-
Known Events:已知的事件
Known Events
Browse 瀏覽
SLA Misses
-
Task Instances:查看每個(gè)task實(shí)例執(zhí)行情況
Task Instances -
Logs:查看所有dag下面對(duì)應(yīng)的task的日志,并且包含檢索
image.png -
Jobs:查看dag的執(zhí)行狀態(tài),開(kāi)始時(shí)間和結(jié)束時(shí)間等指標(biāo)
image.png DAG Runs
Admin:管理員
Pools:
Configuration:查看airflow的配置,即:./airflow_home/airflow.cfg
Users:查看用戶列表,創(chuàng)建用戶,刪除用戶
Connections
我們的Task需要通過(guò)Hook訪問(wèn)其他資源, Hook僅僅是一種訪問(wèn)方式, 就像是JDBC driver一樣, 要連接DB, 我們還需要DB的IP/Port/User/Pwd等信息. 這些信息不太適合hard code在每個(gè)task中, 可以把它們定義成Connection, airflow將這些connection信息存放在后臺(tái)的connection表中. 我們可以在WebUI的Admin->Connections管理這些連接.Variables
Variable 沒(méi)有task_id/dag_id屬性, 往往用來(lái)定義一些系統(tǒng)級(jí)的常量或變量, 我們可以在WebUI或代碼中新建/更新/刪除Variable. 也可以在WebUI上維護(hù)變量.
Variable 的另一個(gè)重要的用途是, 我們?yōu)镻rod/Dev環(huán)境做不同的設(shè)置, 詳見(jiàn)后面的開(kāi)發(fā)小節(jié).XComs
XCom和Variable類(lèi)似, 用于Task之間共享一些信息. XCom 包含task_id/dag_id屬性, 適合于Task之間傳遞數(shù)據(jù), XCom使用方法比Variables復(fù)雜些. 比如有一個(gè)dag, 兩個(gè)task組成(T1->T2), 可以在T1中使用xcom_push()來(lái)推送一個(gè)kv, 在T2中使用xcom_pull()來(lái)獲取這個(gè)kv.
Docs
- 官方文檔
- Github地址
Dag提交-python配置任務(wù)
- DAG 基本參數(shù)配置
default_args = {
'owner': 'airflow',
'depends_on_past': False, # 是否依賴上一個(gè)自己的執(zhí)行狀態(tài)
'start_date': datetime.datetime(2019, 1, 1),
'email': ['wangzhenjun@gmail.com'], # 需要在airflow.cfg中配置下發(fā)件郵箱
'email_on_failure': False,
'email_on_retry': False,
'retries': 1,
'retry_delay': datetime.timedelta(minutes=5),
# 'end_date': datetime(2020, 1, 1), # 結(jié)束時(shí)間,注釋掉也就會(huì)一直執(zhí)行下去
}
- DAG對(duì)象
設(shè)置dag的執(zhí)行周期:schedule_interval.該參數(shù)可以接收cron 表達(dá)式和datetime.timedelta對(duì)象,另外airflow還預(yù)置了一些調(diào)度周期。
preset | Description | cron |
---|---|---|
None | Don’t schedule, use for exclusively “externally triggered” DAGs | |
@once | Schedule once and only once | |
@hourly | Run once an hour at the beginning of the hour | 0 * * * * |
@daily | Run once a day at midnight | 0 0 * * * |
@weekly | Run once a week at midnight on Sunday morning | 0 0 * * 0 |
@monthly | Run once a month at midnight of the first day of the month | 0 0 1 * * |
@yearly | Run once a year at midnight of January 1 | 0 0 1 1 * |
dag = DAG(
'tutorial',
default_args=default_args,
schedule_interval='* * * * *' # 執(zhí)行周期,crontab形式
)
- 定義任務(wù)
在定義這個(gè)任務(wù)的過(guò)程,就像是在寫(xiě)一個(gè) shell 腳本,只是這個(gè)腳本的每個(gè)操作可以有依賴。 不同的操作對(duì)應(yīng)了不同的 Operator,比如 shell 就需要用 BashOperator 來(lái)執(zhí)行。
t1 = BashOperator( #任務(wù)類(lèi)型是bash
task_id='echoDate', #任務(wù)id
bash_command='echo date > /home/datefile', #任務(wù)命令
dag=dag)
- 完整樣例
# coding: utf-8
from airflow import DAG
from airflow.operators.python_operator import PythonOperator
from datetime import datetime, timedelta
# 定義默認(rèn)參數(shù)
default_args = {
'owner': 'wangzhenjun', # 擁有者名稱(chēng)
'depends_on_past': False, # 是否依賴上一個(gè)自己的執(zhí)行狀態(tài)
'start_date': datetime(2019, 1, 15, 10, 00), # 第一次開(kāi)始執(zhí)行的時(shí)間,為格林威治時(shí)間,為了方便測(cè)試,一般設(shè)置為當(dāng)前時(shí)間減去執(zhí)行周期
'email': ['wangzhenjun01@corp.netease.com'], # 接收通知的email列表
'email_on_failure': True, # 是否在任務(wù)執(zhí)行失敗時(shí)接收郵件
'email_on_retry': True, # 是否在任務(wù)重試時(shí)接收郵件
'retries': 3, # 失敗重試次數(shù)
'retry_delay': timedelta(seconds=5) # 失敗重試間隔
}
# 定義DAG
dag = DAG(
dag_id='hello_world', # dag_id
default_args=default_args, # 指定默認(rèn)參數(shù)
# schedule_interval="00, *, *, *, *" # 執(zhí)行周期,依次是分,時(shí),天,月,年,此處表示每個(gè)整點(diǎn)執(zhí)行
schedule_interval=timedelta(minutes=1) # 執(zhí)行周期,表示每分鐘執(zhí)行一次
)
"""
1.通過(guò)PythonOperator定義執(zhí)行python函數(shù)的任務(wù)
"""
# 定義要執(zhí)行的Python函數(shù)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 # 可以在函數(shù)中使用assert斷言來(lái)判斷執(zhí)行是否正常,也可以直接拋出異常
# 定義要執(zhí)行的Python函數(shù)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)
# 定義要執(zhí)行的task 1
t1 = PythonOperator(
task_id='hello_world_1', # task_id
python_callable=hello_world_1, # 指定要執(zhí)行的函數(shù)
dag=dag, # 指定歸屬的dag
retries=2, # 重寫(xiě)失敗重試次數(shù),如果不寫(xiě),則默認(rèn)使用dag類(lèi)中指定的default_args中的設(shè)置
)
# 定義要執(zhí)行的task 2
t2 = PythonOperator(
task_id='hello_world_2', # task_id
python_callable=hello_world_2, # 指定要執(zhí)行的函數(shù)
dag=dag, # 指定歸屬的dag
)
t2.set_upstream(t1) # t2依賴于t1;等價(jià)于 t1.set_downstream(t2);同時(shí)等價(jià)于 dag.set_dependency('hello_world_1', 'hello_world_2')
# 表示t2這個(gè)任務(wù)只有在t1這個(gè)任務(wù)執(zhí)行成功時(shí)才執(zhí)行,
# 或者
t1 >> t2
"""
2.通過(guò)BashOperator定義執(zhí)行bash命令的任務(wù)
"""
hello_operator = BashOperator( #通過(guò)BashOperator定義執(zhí)行bash命令的任務(wù)
task_id='sleep_task',
depends_on_past=False,
bash_command='echo `date` >> /home/py/test.txt',
dag=dag
)
"""
其他任務(wù)處理器:
3.EmailOperator : 發(fā)送郵件
4.HTTPOperator : 發(fā)送 HTTP 請(qǐng)求
5.SqlOperator : 執(zhí)行 SQL 命令
"""
分布式部署
CeleryExecutor
is one of the ways you can scale out the number of workers. For this to work, you need to setup a Celery backend (RabbitMQ, Redis, …) and change your airflow.cfg
to point the executor parameter to CeleryExecutor
and provide the related Celery settings.
我們的生產(chǎn)環(huán)境:
每臺(tái)機(jī)器運(yùn)行的任務(wù)所屬應(yīng)用各不相同,不同應(yīng)用運(yùn)行環(huán)境也不相同,另外不同應(yīng)用也希望達(dá)到集群隔離的目的。如果要實(shí)現(xiàn)這個(gè)功能,需要自己提供隊(duì)列的管理,指定隊(duì)列的任務(wù)節(jié)點(diǎn)會(huì)被調(diào)度到相應(yīng)隊(duì)列的機(jī)器上,相應(yīng)隊(duì)列的機(jī)器也只會(huì)運(yùn)行指定隊(duì)列的任務(wù)節(jié)點(diǎn)。
大部分都是集中在2-3臺(tái)機(jī)器提交,環(huán)境類(lèi)似,各自提交任務(wù),但是任務(wù)通過(guò)主節(jié)點(diǎn)去隨機(jī)分發(fā)到各結(jié)點(diǎn)執(zhí)行,并不能保證環(huán)境的滿足。
現(xiàn)在情況:如果是組內(nèi)使用,各位的環(huán)境差異比較大,首先需要保證各環(huán)境的統(tǒng)一性
面臨的問(wèn)題:
- 官方文檔+網(wǎng)上的關(guān)于分布式的資料不多,官方文檔更多是一筆帶過(guò)。