大規模執行 Apache Airflow 的經驗教訓 - shopify

banq發表於2022-05-24

Apache Airflow是一個編排平臺,支援工作流的開發、排程和監控。在 Shopify,我們已經在生產環境中執行 Airflow 兩年多,用於各種工作流程,包括資料提取、機器學習模型訓練、Apache Iceberg 表維護和DBT 驅動的資料建模。在撰寫本文時,我們目前在 Kubernetes 上執行 Airflow 2.2,使用 Celery 執行器和 MySQL 8。

Shopify 對 Airflow 的使用在過去兩年中急劇擴大。在我們最大的環境中,我們執行了 10,000 多個 DAG,代表了各種各樣的工作負載。該環境平均在給定時刻執行 400 多個任務,每天執行超過 150,000 次執行。隨著 Shopify 內採用率的提高,我們的 Airflow 部署所產生的負載只會增加。由於這種快速增長,我們遇到了一些挑戰,包括檔案訪問速度慢、對 DAG(有向無環圖)能力控制不足、流量水平不規則以及工作負載之間的資源爭用等。

下面我們將分享一些我們學到的經驗教訓和我們構建的解決方案,以便大規模執行 Airflow。

1. 使用雲端儲存時檔案訪問速度可能會很慢
快速檔案訪問對於 Airflow 環境的效能和完整性至關重要。明確定義的檔案訪問策略可確保排程程式能夠快速處理 DAG 檔案並讓您的作業保持最新。

Airflow 透過反覆掃描和重新解析配置的 DAG 目錄中的所有檔案來保持其工作流的內部表示是最新的。必須經常掃描這些檔案,以保持每個工作負載的磁碟上真實資料來源與其在資料庫中的表示之間的一致性。這意味著 DAG 目錄的內容必須在單個環境中的所有排程程式和worker之間保持一致(Airflow 提出了一些實現這一點的方法)。

經過一些實驗,我們發現我們可以透過在 Kubernetes 叢集中執行 NFS(網路檔案系統)伺服器來極大地提高 Airflow 環境的效能。

在大規模執行 Airflow 時確保快速檔案訪問時要考慮的另一個因素是檔案處理效能。Airflow 具有高度可配置性,並提供多種方式來調整後臺檔案處理(例如排序模式、 並行性超時)。這使您可以根據要求最佳化互動式 DAG 開發或排程程式效能的環境。

2. 增加後設資料量會降低Airflow 操作
在正常規模的 Airflow 部署中,至少在連續執行的頭幾年內,後設資料量導致的效能下降不會成為問題。

然而,在規模上,後設資料開始快速積累。一段時間後,這可能會開始對資料庫產生額外的負載。這在 Web UI 的載入時間中很明顯,在 Airflow 升級期間更是如此,在此期間遷移可能需要數小時。

經過反覆試驗,我們確定了 28 天的後設資料保留策略,並實現了一個簡單的 DAG,它使用 PythonOperator 中的 ORM(物件-關係對映)查詢從包含歷史資料(DagRuns、TaskInstances、Logs)的任何表中刪除行、TaskRetries 等)。我們選擇了 28 天,因為這為我們提供了足夠的歷史記錄來管理事件和跟蹤歷史工作績效,同時將資料庫中的資料量保持在合理的水平。

不幸的是,這意味著我們的環境不支援依賴持久作業歷史的 Airflow 功能(例如,長時間執行的回填)。這對我們來說不是問題,但根據您的保留期限和 Airflow 的使用情況,它可能會導致問題。
作為自定義 DAG 的替代方法,Airflow最近增加db clean了對可用於刪除舊後設資料的命令的支援。此命令在 Airflow 版本 2.3 中可用。

3. DAG 很難與使用者和團隊聯絡起來
在多租戶環境中(尤其是在大型組織中)執行 Airflow 時,能夠將 DAG 追溯到個人或團隊非常重要。為什麼?因為如果一項工作失敗、丟擲錯誤或干擾其他工作負載,我們的管理員可以快速聯絡相應的使用者。

如果所有 DAG 都直接從一個儲存庫部署,我們可以簡單地使用它git blame來追蹤作業所有者。然而,由於我們允許使用者從他們自己的專案中部署工作負載(甚至在部署時動態生成作業),這變得更加困難。

為了方便追溯 DAG 的來源,我們引入了 Airflow名稱空間的登錄檔,我們將其稱為 Airflow 環境的清單檔案。

清單檔案是一個 YAML 檔案,使用者必須在其中為其 DAG 註冊一個名稱空間。在此檔案中,它們將包含有關作業所有者和源 github 儲存庫(甚至源 GCS 儲存桶)的資訊,併為其 DAG 定義一些基本限制。我們為每個環境維護一個單獨的清單,並將其與 DAG 一起上傳到 GCS。

4. DAG 作者有很大的權力
透過允許使用者直接編寫 DAG 並將其上傳到共享環境,我們賦予了他們很大的權力。由於 Airflow 是我們資料平臺的核心元件,它與許多不同的系統相關聯,因此工作具有廣泛的訪問許可權。雖然我們信任我們的使用者,但我們仍然希望對他們在給定的 Airflow 環境中可以做什麼和不可以做什麼保持一定程度的控制。這在規模上尤其重要,因為 Airflow 管理員無法在所有作業投入生產之前對其進行審查。
為了建立一些基本的防護機制,我們實現了一個DAG 策略,它從前面提到的 Airflow 清單中讀取配置,並透過引發AirflowClusterPolicyViolation.
根據清單檔案的內容,此策略將對 DAG 檔案應用一些基本限制,例如:

  • DAG ID 必須以現有名稱空間的名稱為字首,以獲得所有權。
  • DAG 中的任務只能將任務排入指定的 celery 佇列——稍後會詳細介紹。
  • DAG 中的任務只能在指定的池中執行,以防止一個工作負載佔用另一個工作負載的容量。
  • 此 DAG 中的任何 KubernetesPodOperators 只能在指定的 名稱空間中啟動 pod ,以防止訪問其他名稱空間的機密。
  • DAG 中的任務只能將 pod 啟動到指定的外部 kubernetes 叢集集

可以擴充套件此策略以強制執行其他規則(例如,僅允許有限的一組運算子),甚至改變任務以符合特定規範(例如,為 DAG 中的所有任務新增特定於名稱空間的執行超時) .

5. 確保負載的一致分佈是困難的
為您的 DAG 計劃間隔使用絕對間隔是非常誘人的——只需將 DAG 設定為執行一次timedelta(hours=1),您就可以走開,安全地知道您的 DAG 將大約每小時執行一次。但是,這可能會導致大規模的問題。

當使用者合併大量自動生成的 DAG,或者編寫一個 Python 檔案在解析時生成許多 DAG 時,會同時建立所有的 DAGRun。這會產生大量流量,可能會使 Airflow 排程程式以及作業正在使用的任何外部服務或基礎設施(例如 Trino 叢集)過載。

6.資源爭用點多
Airflow 內部有很多可能的資源爭用點,透過一系列實驗性的配置更改很容易最終陷入瓶頸。其中一些資源衝突可以在 Airflow 中處理,而其他資源衝突可能需要一些基礎架構更改。

更多點選標題

相關文章