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

Reiji Kainuma

May 17, 2022
Tweet

More Decks by Reiji Kainuma

Other Decks in Programming

Transcript

  1. Airflow2

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

    View Slide

  2. 自己紹介
    @reizist

    Web Backend / Infra / Data (Infra)

    R
    なんとかという会社で

    データエンジニア
    魚を捌いて食べるのが好きで、海沿い
    への移住を検討しています
    2 / 24

    View Slide

  3. Airflow1.10.15/CloudComposer1


    Airflow2.2.1/CloudComposer2


    upgrade
    した事例を紹介します
    3 / 24

    View Slide

  4. Airflow
    を使っている方

    Airflow
    を使っているがまだ1
    系の方

    は参考になるかもしれません
    4 / 24

    View Slide

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

    View Slide

  6. Airflow2(Composer2)
    の恩恵
    /
    モチベーション
    Airflow1
    系のサポート体制への懸念
    GCP
    においても2023/3
    でAirflow1
    を非サポート化
    daily job
    を落とさず毎日朝11
    時までに必ずデータを揃えたい都
    合上安心できるサポート体制が必要
    6 / 24

    View Slide

  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

    View Slide

  8. Airflow2(Composer2)
    の恩恵
    /
    モチベーション
    TaskGroup
    が使える
    グループ化したいTask
    をSubDagOperator
    で実現していた
    =>
    稀に想定以上のリソースを要求しworker
    が落ちる障害
    非推奨なSubDagOperator
    からの脱却
    8 / 24

    View Slide

  9. Airflow2(Composer2)
    の恩恵
    /
    モチベーション
    Composer2
    によるインフラリソース管理の柔軟化
    Airflow1
    時はdaily job
    実行時にnode
    数を自前スケールしていた

    => GKE
    のAutoPilot
    によりnode
    管理が不要に
    スケジューラのマシンタイプや実行数は指定不可だった

    =>
    スケジューラの冗長化が可能になりより堅牢に
    daily job
    は半日しっかり動き半日ほとんど動かない

    =>
    インフラリソースの最適化が見込めた 9 / 24

    View Slide

  10. Airflow2(Composer2)
    の恩恵
    /
    モチベーション
    総じてdaily job
    を動かすtask runner
    としてより安全に/
    運用コスト
    の削減が見込めた
    10 / 24

    View Slide

  11. Airflow2
    への
    upgrade
    方法
    基本は公式Doc
    を読んで順に対応すればOK
    airflow API
    が変わっていたりmodule path
    が変わっていたりする
    その他細かい変更はあるのでAirflow1/Airflow2
    の両ソースをパッと
    見られる環境にしておくと安心
    11 / 24

    View Slide

  12. Airflow2
    への
    upgrade
    方法
    事前制約: daily job
    は停止できない
    Airflow2
    切り替え後不調時のrollback
    環境が必須
    Airflow 1
    系と2
    系の両環境を用意しDAG
    のPause/Unpause
    を利用
    検証時に発覚: Airflow2
    系でSubDagOperator
    が動かない現象が発生

    => TaskGroup
    への完全移行が必須
    12 / 24

    View Slide

  13. Airflow2
    への
    upgrade
    方法
    Airflow1
    系はSubDagOperator

    Airflow2
    系はTaskGroup
    で動かす必要があった
    とはいえ可能な限りソースコードの差分を小さくしたい

    =>
    タスクの依存関係を作るメソッドを切り出し、SubDag
    でwrap

    るメソッドとTaskGroup
    でwrap
    するメソッドに分離
    13 / 24

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  18. Airflow2
    切り替え後の話
    障害対応が減り安定稼働した
    昨期2021/10 - 2022/3
    で失敗通知を受け取り手動で再実行する
    など何らかの人間による対応をした件数: 40
    件ほど
    今期2022/4 - : 3

    外部サービスの不調などAirflow
    とは無関係の症状が主で
    Airflow
    起因の対応は0

    18 / 24

    View Slide

  19. 補足
    : SubDagOperator
    を辞める
    SubDagOperator
    に on_failure_callback
    を指定し失敗時にslack

    メンションを受け取る運用
    => SubDag
    内のどのtask
    が落ちてもSubDag
    自体も失敗する挙動

    => TaskGroup
    にはcallback
    は指定できない

    =>
    全task
    にcallback
    を指定することで失敗を検知
    19 / 24

    View Slide

  20. 補足
    : Airflow1=>Airflow2
    へのデータ移行
    airflow_db backup
    のための公式script
    がある
    ただしAirflow2.2
    ではexecution_date
    カラムが廃止されるなどの
    schema
    変更があるので2.0
    系を挟む必要がある
    SubDag
    を辞める都合上1
    系データのimport
    を頑張る必要もないと
    判断
    ただし1
    系のデータはBQ
    にEmbulk
    でexport
    しておいた
    20 / 24

    View Slide

  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

    View Slide

  22. 補足
    : CloudLogging

    sink error
    が発生
    BQ
    のquery
    実行ログをAudit Log
    として残していた
    (
    おそらくBigQueryOperator
    からBigQueryExecuteQueryOperator
    に変わったことで)stderr
    のschema
    が変わった
    gcp_audit_log.stderr
    テーブルの再作成で対処した
    22 / 24

    View Slide

  23. まとめ
    堅牢化/
    コスト削減の目的で

    Airflow2/CloudComposer2
    にupgrade
    した
    障害対応数は減って安定化した
    celery/worker_concurrency
    調整によるインフラリソースの最適化
    を今後予定
    23 / 24

    View Slide

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

    View Slide