Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Airflow1=>Airflow2へのupgrade 事例紹介

Airflow1=>Airflow2へのupgrade 事例紹介

AIrflow 1.10.15/CloudComposer1 で動く本番環境を
Airflow 2.2.1/CloudComposer2 にupgradeしたので事例の紹介です。

https://github.com/reizist/slide/tree/master/datatech_casual%232

A3ae651ab614249880dd9fad4fd0cee7?s=128

Reiji Kainuma

May 17, 2022
Tweet

More Decks by Reiji Kainuma

Other Decks in Programming

Transcript

  1. Airflow2 に upgrade した事例紹介 @reizist 1 / 24

  2. 自己紹介 @reizist Web Backend / Infra / Data (Infra) R

    なんとかという会社で データエンジニア 魚を捌いて食べるのが好きで、海沿い への移住を検討しています 2 / 24
  3. Airflow1.10.15/CloudComposer1 を Airflow2.2.1/CloudComposer2 に upgrade した事例を紹介します 3 / 24

  4. Airflow を使っている方 Airflow を使っているがまだ1 系の方 は参考になるかもしれません 4 / 24

  5. アジェンダ Airflow2 upgrade の恩恵/ モチベーション Airflow2 へのupgrade 方法 Airflow2 切り替え後の話

    補足 5 / 24
  6. Airflow2(Composer2) の恩恵 / モチベーション Airflow1 系のサポート体制への懸念 GCP においても2023/3 でAirflow1 を非サポート化

    daily job を落とさず毎日朝11 時までに必ずデータを揃えたい都 合上安心できるサポート体制が必要 6 / 24
  7. Airflow1 # Operator の定義が冗長的 extract = PythonOperator(task_id="extract", python_callable=extract) transform =

    PythonOperator(task_id="transform", python_callable=transform) load = PythonOperator(task_id="load", python_callable=load) extract >> transform >> load # 依存関係を明示的に定義 Airflow2 order_data = extract() order_summary = transform(order_data) load(order_summary["total_order_value"]) Airflow2(Composer2) の恩恵 / モチベーション DAG の記述量が減り簡素化できる"TaskFlow API" 後述の理由によりAirflow1 と書き方を継続 7 / 24
  8. Airflow2(Composer2) の恩恵 / モチベーション TaskGroup が使える グループ化したいTask をSubDagOperator で実現していた =>

    稀に想定以上のリソースを要求しworker が落ちる障害 非推奨なSubDagOperator からの脱却 8 / 24
  9. Airflow2(Composer2) の恩恵 / モチベーション Composer2 によるインフラリソース管理の柔軟化 Airflow1 時はdaily job 実行時にnode

    数を自前スケールしていた => GKE のAutoPilot によりnode 管理が不要に スケジューラのマシンタイプや実行数は指定不可だった => スケジューラの冗長化が可能になりより堅牢に daily job は半日しっかり動き半日ほとんど動かない => インフラリソースの最適化が見込めた 9 / 24
  10. Airflow2(Composer2) の恩恵 / モチベーション 総じてdaily job を動かすtask runner としてより安全に/ 運用コスト

    の削減が見込めた 10 / 24
  11. Airflow2 への upgrade 方法 基本は公式Doc を読んで順に対応すればOK airflow API が変わっていたりmodule path

    が変わっていたりする その他細かい変更はあるのでAirflow1/Airflow2 の両ソースをパッと 見られる環境にしておくと安心 11 / 24
  12. Airflow2 への upgrade 方法 事前制約: daily job は停止できない Airflow2 切り替え後不調時のrollback

    環境が必須 Airflow 1 系と2 系の両環境を用意しDAG のPause/Unpause を利用 検証時に発覚: Airflow2 系でSubDagOperator が動かない現象が発生 => TaskGroup への完全移行が必須 12 / 24
  13. Airflow2 への upgrade 方法 Airflow1 系はSubDagOperator Airflow2 系はTaskGroup で動かす必要があった とはいえ可能な限りソースコードの差分を小さくしたい

    => タスクの依存関係を作るメソッドを切り出し、SubDag でwrap す るメソッドとTaskGroup でwrap するメソッドに分離 13 / 24
  14. Airflow2 への upgrade 方法 def _tasks(dag, child_dag_name, args): start_task =

    dummy_operator(task_id="start_task") task = PythonOperator(task_id="main_task", python_callable=_main) end_task = dummy_operator(task_id="end_task") start_task >> task >> end_task def build_xxx_dag(parent_dag_name, child_dag_name, args): dag_name = "%s.%s" % (parent_dag_name, child_dag_name) with DAG(dag_id=dag_name, default_args=args) as dag: _tasks(dag, args) return dag def build_xxx_task_group(dag, args): with TaskGroup("xxx_tasks") as xxx_tasks: _tasks(dag, args) return xxx_tasks 14 / 24
  15. * Airflow1 系: daily_task_for_v1.py dag = DAG(dag_id=DAG_NAME, default_args=default_args, schedule_interval="00 15

    * * *") daily_start_task = DummyOperator(task_id="daily_start_task", dag=dag) daily_end_task = DummyOperator(task_id="daily_end_task", dag=dag) xxx_tasks = SubDagOperator( task_id="xxx_tasks", subdag=build_xxx_dag(DAG_NAME, "xxx_tasks", default_args), default_args=default_args, dag=dag, ) daly_start_task >> xxx_tasks >> daily_end_task * Airflow2 系: daily_task_for_v2.py dag = DAG(dag_id=DAG_NAME, default_args=default_args, schedule_interval="00 15 * * *") daily_start_task = DummyOperator(task_id="daily_start_task", dag=dag) daily_end_task = DummyOperator(task_id="daily_end_task", dag=dag) with dag: xxx_tasks = build_xxx_task_group(dag, default_args) daly_start_task >> xxx_tasks >> daily_end_task Airflow2 への upgrade 方法 15 / 24
  16. Airflow2 への upgrade 方法 master branch では daily_task_for_v1.py を、 version2

    branch では daily_task_for_v2.py を使う _tasks() 内をいじらない限りconflict は発生しない master branch へのmerge をtrigger に version2 branch へauto merge master branch ではAirflow1 が、 version2 branch ではAirflow2 がそれぞれ最新のソースコードで 動く状態を担保 16 / 24
  17. master version2 topic workflow-airflow 1 Cloud Composer workflow-airflow 2 Cloud

    Composer deploy deploy 安定稼働後 merge workflow-airflow 2 Cloud Composer deploy 削除 auto merge TaskGroup 化 module path の修正 17 / 24
  18. Airflow2 切り替え後の話 障害対応が減り安定稼働した 昨期2021/10 - 2022/3 で失敗通知を受け取り手動で再実行する など何らかの人間による対応をした件数: 40 件ほど

    今期2022/4 - : 3 件 外部サービスの不調などAirflow とは無関係の症状が主で Airflow 起因の対応は0 件 18 / 24
  19. 補足 : SubDagOperator を辞める SubDagOperator に on_failure_callback を指定し失敗時にslack で メンションを受け取る運用

    => SubDag 内のどのtask が落ちてもSubDag 自体も失敗する挙動 => TaskGroup にはcallback は指定できない => 全task にcallback を指定することで失敗を検知 19 / 24
  20. 補足 : Airflow1=>Airflow2 へのデータ移行 airflow_db backup のための公式script がある ただしAirflow2.2 ではexecution_date

    カラムが廃止されるなどの schema 変更があるので2.0 系を挟む必要がある SubDag を辞める都合上1 系データのimport を頑張る必要もないと 判断 ただし1 系のデータはBQ にEmbulk でexport しておいた 20 / 24
  21. 補足 : CloudComposer2 の地味な変更点 backend db がMySQL からPostgreSQL に変わっている Airflow

    の仕組み上のretry とは別にSQL 経由でnon successed な task をrerun する自前の仕組みを使っているため影響した SELECT unfinished_task.dag_id, task_id, state, operator, IF(state = 'queued', (TO_SECONDS(NOW()) - TO_SECONDS(COALESCE(end_date, start_date))), --- `TO_SECONDS` はMySQL にのみ組み込み (TO_SECONDS(NOW()) - TO_SECONDS(start_date)) ) AS duration_time, unfinished_task.execution_date, start_date FROM ( SELECT * FROM task_instance WHERE state IN ('running', 'queued', 'shutdown') AND execution_date LIKE '{}%' AND ..... ) unfinished_task 21 / 24
  22. 補足 : CloudLogging の sink error が発生 BQ のquery 実行ログをAudit

    Log として残していた ( おそらくBigQueryOperator からBigQueryExecuteQueryOperator に変わったことで)stderr のschema が変わった gcp_audit_log.stderr テーブルの再作成で対処した 22 / 24
  23. まとめ 堅牢化/ コスト削減の目的で Airflow2/CloudComposer2 にupgrade した 障害対応数は減って安定化した celery/worker_concurrency 調整によるインフラリソースの最適化 を今後予定

    23 / 24
  24. ご清聴ありがとうございました 24 / 24