[譯] Robinhood 為什麼使用 Airflow

cf020031308發表於2018-07-13

Robinhood 通過定時作業批處理大量任務。這些作業涵蓋了從資料分析和指標彙總到經紀業務如股息支付的範圍。我們起初使用 cron 來排程這些工作,但隨著它們的數量和複雜性的增加,這越來越具有挑戰性:

  • 依賴管理難。使用 cron,我們得用上游作業的最壞預期時長來安排下游作業。隨著這些作業的複雜度及其依賴關係的成規模增加,這越來越難。
  • 失敗處理和警報必須由作業管理。在存在依賴關係的情況下,如果作業不能處理重試和上游故障,就只能靠工程師隨叫隨到。
  • 回溯難。我們得篩查日誌或警報來檢查作業在過去某一天的表現。

為了滿足排程需求,我們決定放棄 cron,將其替換為能解決上述問題的東西。我們調研了一些開源替代品,如 PinballAzkaban 以及 Luigi,最終決定用 Airflow

Pinball

Pinball 由 Pinterest 開發,具有分散式、可水平擴充套件的工作流管理和排程系統的許多功能。它解決了上面提到的很多問題,但文件很少,社群相對較小。

Azkaban

由 LinkedIn 開發的 Azkaban 可能是我們考慮過的替代品中最古老的。它使用屬性檔案來定義工作流,而大多數新的替代方案使用程式碼。這使得定義複雜工作流程變得更加困難。

Luigi

由 Spotify 開發的 Luigi 擁有一個活躍的社群,可能在我們的調研中最接近 Airflow。它使用 Python 來定義工作流,並帶有一個簡單的 UI。但是 Luigi 沒有排程程式,使用者仍然需要依賴 cron 來安排作業。

你好,Airflow!

由 Airbnb 開發的 Airflow 擁有一個持續增長的社群,似乎是最適合我們目的的。它是一個可水平擴充套件的分散式工作流管理系統,允許我們使用 Python 程式碼指定複雜的工作流。

依賴管理

Airflow 使用操作符作為定義任務的基本抽象單元,並使用 DAG(有向無環圖)通過一組操作符定義工作流。操作符是可擴充套件的,這使得自定義工作流變得容易。操作符分為3種型別:

  • 動作執行某些操作的操作符,例如執行 Python 函式或提交 Spark Job。
  • 轉移在系統之間移動資料的操作符,例如從 Hive 到 Mysql 或從 S3 到 Hive。
  • 感測器在滿足特定條件時觸發依賴網中的下游任務,例如在下游使用之前檢查 S3 上的某個檔案是否可用。感測器是 Airflow 的強大功能,使我們能夠建立複雜的工作流程並輕鬆管理其前提條件。

下面是一個示例,說明不同型別的感測器如何用於典型的 ETL(資料提取轉換與載入)工作流程。該示例使用感測器操作符等待資料可用,並使用轉移操作符將資料移動到所需位置。然後將動作操作符用於轉換階段,然後使用轉移操作符載入結果。最後,我們使用感測器操作符來驗證結果是否已正確儲存。

[譯] Robinhood 為什麼使用 Airflow

| 感測器 -> 轉移 -> | 動作 | -> 轉移 -> 感測器 |
|      提取        |  轉換 |      載入       |
複製程式碼

使用不同型別的 Airflow 操作符的 ETL 工作流程

故障處理和監控

Airflow 允許我們為單個任務配置重試策略配置,並可設定在出現故障、重試以及執行的任務長於預期的情況下告警。Airflow 有直觀的 UI,帶有一些用於監控和管理作業的強大工具。它提供了作業的歷史檢視和控制作業狀態的工具 —— 例如,終止正在執行的作業或手動重新執行作業。 Airflow 的一個獨特功能是能夠使用作業資料建立圖表。這使我們能夠構建自定義視覺化以緊密監視作業,並在排查作業和排程問題時充當一個很好的除錯工具。

可擴充套件

Airflow 操作符是使用 Python 類定義的。這使得通過擴充套件現有操作符來定義自定義、可重用的工作流非常容易。我們在內部構建了一大套自定義操作符,其中一些值得注意的例子是 OpsGenieOperator,DjangoCommandOperator 和 KafkaLagSensor。

更智慧的 Cron

Airflow DAG 是使用 Python 程式碼定義的。這使我們能夠定義比 cron 更復雜的排程。例如,我們的一些 DAG 只需在交易日執行。而如果用簡陋的 cron,我們得設定在所有的工作日執行,然後在應用程式中處理市場假期的情況。

我們還使用 Airflow 感測器在市場收盤後立即開始作業,即使當天只有半天開盤。以下示例通過為需要複雜的排程的工作流自定義操作符,來在給定日期根據市場時間動態更新。

[譯] Robinhood 為什麼使用 Airflow

在給定日期根據市場時間動態排程的工作流

回填

我們使用 Airflow 進行指標聚合和批量處理資料。隨著需求的不斷變化,我們有時需要回頭更改我們彙總某些指標或新增新指標的方式。這需要能往過去任意時間段回填資料。 Airflow 提供了一個命令列工具,讓我們能使用單個命令跨任意時間段進行回填,也可以從 UI 觸發回填。我們使用 Celery(由我們的 Ask Solem 製作)往 worker box 中分發這些任務。 Celery 的分發能力使我們能夠在執行回填時使用更多 worker box,從而使回填變得快捷方便。

常見的陷阱和弱點

我們目前使用的是 Airflow 1.7.1.3,它在生產中執行良好,但有自己的弱點和陷阱

  • 時區問題 —— Airflow 依賴系統時區(而不是 UTC)進行排程。這要求整個 Airflow 設定在同一時區執行。
  • 排程程式分開執行預定作業和回填作業。這可能會導致奇怪的結果,例如回填不符合 DAG 的 max_active_runs 配置。
  • Airflow 主要用於資料批處理,因而其設計師決定總是先等待一個間隔後再開始作業。因此,對一個計劃在每天午夜執行的作業,其上下文中傳入的執行時間為“2016-12-31 00:00:00”,但實際卻在“2017-01-01 00:00:00”才真正執行。這可能會讓人感到困惑,尤其是在不定期執行的作業中。
  • 意外的回填 —— 預設情況下,Airflow 會在 DAG 從暫停中恢復時或在新增一個 start_date 為過去時間的新 DAG 時嘗試回填錯過的任務。雖然這種行為是可預料的,但終究沒有辦法繞過,如果一個作業不應該回填,這就會導致問題。Airflow 1.8 引入了最近操作符 來解決這個問題。

總結

Airflow 迅速發展成了我們 Robinhood 基礎設施的重要組成部分。使用 Python 程式碼和可擴充套件 API 定義 DAG 的能力使 Airflow 成為可配置且功能強大的工具。希望這篇文章對於任何探索排程和工作流管理工具以滿足其自身需求的人都很有用。我們很樂意回答任何問題。如果這種東西對你很有意思,考慮下我們的招聘

感謝 Arpan ShahAravind Gottipati,和 Jack Randall

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章