Share
Embed
ワークフローオーケストレーション入門
「Data Engineering Study #23 Data orchestration 特集」の発表資料です
イベントページ: https://forkwell.connpass.com/event/310011/
Satsuki Nagae
March 05, 2024
Transcript
123 slides
-
長江 五月 自己紹介 4 @nsakki55 ブログ: https://nsakki55.hatenablog.com/ AWSでML基盤を構築する記事を書いてます 業務 ・MLOps
・MLモデリング ・広告データ分析 CyberAgent AI事業本部 Dynalyst データサイエンティスト マネージャー -
11 ワークフローオーケストレーションツール ワークフローオーケストレーションを実行するツール Infrastructure Infrastructure Step 1 Step 2 Trigger
System ワークフローオーケストレーションツール -
12 類似語 データオーケストレーション 機械学習オーケストレーション 機械学習ワークフロー データワークフロー ワークフローオーケストレーション ワークフローエンジン(ツールとしての意味) ワークフロー管理 パイプラインオーケストレーション
機械学習に着目 機械学習パイプライン データパイプライン データに着目 -
15 ワークフローオーケストレーションツールの歴史 CRON時代 リレーショナルデータベース時代 データウェアハウス・データ統合時代 ビッグデータ時代 モダンデータスタック時代 1970~ 1980~ 1990~
2000~ 2010~ 参考: A Brief History of Workflow Orchestration -
16 ワークフローオーケストレーションツールの歴史 CRON時代 リレーショナルデータベース時代 データウェアハウス・データ統合時代 ビッグデータ時代 モダンデータスタック時代 1970~ 1980~ 1990~
2000~ 2010~ 参考: A Brief History of Workflow Orchestration -
17 CRON時代 1974年 UNIXにCRON導入 指定された時刻にコマンドを実行する 0 0 0 1 1
* ./workflow.sh 実行例 -
18 ワークフローオーケストレーションツールの歴史 CRON時代 リレーショナルデータベース時代 データウェアハウス・データ統合時代 ビッグデータ時代 モダンデータスタック時代 1970~ 1980~ 1990~
2000~ 2010~ 参考: A Brief History of Workflow Orchestration -
19 リレーショナルデータベース時代 1979年 商用リレーショナルデータベースOracle v2リリース 1995年 Oracleがジョブキューを導入(DBMS_JOB) データベース用コードの定期的な実行をスケジュール DECLARE job_number
NUMBER; BEGIN DBMS_JOB.SUBMIT( job => job_number, what => 'BEGIN YOUR_PROCEDURE_NAME; END;', next_date => SYSDATE, interval => 'SYSDATE + 1' ); COMMIT; END; ジョブ例 -
20 ワークフローオーケストレーションツールの歴史 CRON時代 リレーショナルデータベース時代 データウェアハウス・データ統合時代 ビッグデータ時代 モダンデータスタック時代 1970~ 1980~ 1990~
2000~ 2010~ 参考: A Brief History of Workflow Orchestration -
21 データウェアハウス・データ統合時代以前 アプリケーション データベース エクセルファイル スクリプトをCRON実行 DBMS_JOB 人手で作業 データソース 集計方法
複数のデータソースごとデータを処理していた -
22 データウェアハウス・データ統合時代 アプリケーション データベース エクセルファイル データウェアハウス データ統合 Extract Transform Load
複数のデータソースにまたがってデータを処理するのが主流に -
24 ワークフローオーケストレーションツールの歴史 CRON時代 リレーショナルデータベース時代 データウェアハウス・データ統合時代 ビッグデータ時代 モダンデータスタック時代 1970~ 1980~ 1990~
2000~ 2010~ 参考: A Brief History of Workflow Orchestration -
26 ビッグデータ時代 アプリケーション データベース エクセルファイル データレイク Extract Load Transform データ活用
オンプレ環境のHadoopエコシステムでデータ基盤構築が主流に -
28 ワークフローツール第1世代 2010 Hadoopジョブのオーケストレーションシステム Hadoopジョブやデータ取り込み・書き込みなど 長時間実行されるバッチジョブの管理 Yahoo Oozie 2012 Spotify
Luigi 2014 LinkedIn Azkaban Hadoopジョブを実行するバッチワークフローの ジョブスケジューラー 2015 Airbnb Airflow ワークフローをプログラムで作成・スケジュール 監視するためのプラットフォーム 開発 名称 概要 -
29 ワークフローオーケストレーションツールの歴史 CRON時代 リレーショナルデータベース時代 データウェアハウス・データ統合時代 ビッグデータ時代 モダンデータスタック時代 1970~ 1980~ 1990~
2000~ 2010~ 参考: A Brief History of Workflow Orchestration -
30 モダンデータスタック時代 Big Query(GCP)がGA Redshift(AWS)がGA Sparkを事業化したDatabrics設立 SnowflakeがGA Kafkaを事業化したConfluent設立 2011 2013
2014 オンプレから安価で高速なクラウドへ ストリームデータ処理技術が発達 -
31 Modern Data Stack Data Stackとは? データ基盤を構成する製品群のこと データベース・BIツール・ETL製品・ワークフローツールなど Modern Data
Stackとは? 特定のアーキテクチャ・技術・ソリューションを指す言葉ではない 従来のData Stackの課題を解決しようする技術トレンドの総称 -
33 ワークフローツール第2世代の登場 DigdagがOSS化 StepFunctions(AWS)がGA Prefectリリース ArgoがOSS化 Dagsterリリース 2016 2017 2018
2019 Cloud Composer(GCP)がGA -
34 主要ワークフローツールの変遷まとめ CRON RDMS_JOB PowerCenter Oozie Luigi Azkaban Airflow Digdag
Argo Prefect Dagster CRON時代 リレーショナル データベース時代 データウェアハウス・ データ統合時代 ビッグデータ時代 モダンデータ スタック時代 -
39 データパイプラインの課題 イベントログ マスターデータ 手動入力データ 抽出 クレンジング 結合 書き込み 抽出
抽出 データ変換 Slack通知 書き込み 型変換 手動実行 バッチ実行 チームA管理 チームB管理 スクリプトで 処理を記述 レポートテーブル 日販管理 -
40 データパイプラインへのワークフローツール導入 手動リトライ 自動リトライ 自前実装 タスク定義のみ 複数箇所 一箇所 チームごと管理 チーム横断で管理
エラー対応 実行順序制御 実行ログ確認 データサイロ化 導入前 導入後 -
41 機械学習パイプラインの課題 生データ 抽出 前処理 学習 学習 学習 評価 デプロイ
特徴量ストア モデルストア 並列学習 実験管理 GPU利用 jupyter notebookに処理を記述 データサイエンティストが管理 -
42 機械学習パイプラインへのワークフローツール導入 jupyter notebook スクリプト 個人 チーム 困難 比較的容易 パイプライン管理
運用者 複数モデル管理 導入前 導入後 -
44 ワークフローとDAGの関係 A B C D A B C D
DAG Not DAG 実行順序を事前に決定できる 最後のタスクが成功=ワークフローの成功 メリット -
45 なぜDAGがワークフローツールに普及したか 初期のワークフローツールはHadoopジョブをマークアップ言語で記述 MapReduce マークアップ言語 Map Task Reduce Task 出力
入力 Map Task Map Task YAML・XMLなど ループ・相互依存 を表現できない 全てのワークフロー をDAGとして表現 DAGにする必要性がない説もある You Probably Don’t Need a DAG -
6つのワークフローツールの特徴比較 Step Functions 特徴 シンプル 手軽 k8sと連携 Python DAG 活用事例が豊富
自然なPython 記法での開発 データ運用に特化 サーバレス AWSサービス ワークフロー 実装言語 digファイル (YAML) k8s manifest (YAML) Python (Operator) Python (Flow) Python (Job) GUI操作 JSON 利用形態 OSS OSS OSS SaaS クラウドマネージド OSS SaaS OSS SaaS クラウドマネージド 学習コスト 低 中 高 高 高 低 -
52 SaaS・マネージドサービスとして提供 Astronomer Amazon Managed Workflows for Apache Airflow Cloud
Composer Azure data factory -
54 実装例 import json import pendulum from airflow.models.dag import DAG
from airflow.operators.python import PythonOperator with DAG( "tutorial_dag", default_args={"retries": 2}, description="DAG tutorial", schedule="@daily", start_date=pendulum.datetime(2021, 1, 1, tz="UTC"), catchup=False, tags=["example"], ) as dag: DAGの設定 DAGコンテキストマネージャを使用 ・実行スケジュール ・リトライ -
55 実装例 def extract(**kwargs): ti = kwargs["ti"] data_string = '{"1001":
301.27, "1002": 433.21, "1003": 502.22}' ti.xcom_push("order_data", data_string) def transform(**kwargs): ti = kwargs["ti"] extract_data_string = ti.xcom_pull(task_ids="extract", key="order_data") order_data = json.loads(extract_data_string) total_order_value = 0 for value in order_data.values(): total_order_value += value total_value = {"total_order_value": total_order_value} total_value_json_string = json.dumps(total_value) ti.xcom_push("total_order_value", total_value_json_string) def load(**kwargs): ti = kwargs["ti"] total_value_string = ti.xcom_pull(task_ids="transform", key="total_order_value") total_order_value = json.loads(total_value_string) Python Operatorで実行する 関数を作成 タスク間のデータ受け渡し -
56 実装例 extract_task = PythonOperator( task_id="extract", python_callable=extract, ) transform_task =
PythonOperator( task_id="transform", python_callable=transform, ) load_task = PythonOperator( task_id="load", python_callable=load, ) extract_task >> transform_task >> load_task Operatorのインスタンスを作成 DAGの作成 -
61 Digdagの要素 Task Executor Task sh> py> email> bq> loop>
redshift> if> ECS Operator Regisotry Command Executor -
62 Digファイルでワークフローを記述 timezone: UTC +setup: echo>: start ${session_time} +disp_current_date: echo>:
${moment(session_time).utc().format('YYYY-MM-DD HH:mm:ss Z')} +repeat: for_each>: order: [first, second, third] animal: [dog, cat] _do: echo>: ${order} ${animal} _parallel: true +teardown: echo>: finish ${session_time} YAML記法 + Dig独自の記法 -
64 YAMLの欠点を補填 利点 ・シンプルで理解しやすい ・プログラムでパース・生成できる ・シンタックスハイライト可能 欠点 ・外部ファイルのincludeができない ・変数の埋め込みができない ・プログラムが書けない
参考: DigdagはなぜYAMLなのか? Digファイルならできる -
66 実装例 timezone: UTC schedule: daily>: 01:00:00 _export: !include: 'plugin.yml'
workflow_name: sample_workflow task_date: ${moment(session_time).utc().format("YYYYMMDDHH")} +prepare: sh>: tasks/prepare_data1.sh +analyse: _export: bar: 2 +sub_step1: py>: tasks.MyWorkflow.analyze_step1 +sub_step2: py>: tasks.MyWorkflow.analyze_step2 スケジュール設定 外部プラグイン読み込み・変数宣言 ・JavaScriptプログラム展開 タスクグループ -
71 6種類のTemplate Container Script Resource Suspend Steps Dags 実行コンテナの設定 コンテナ内での実行スクリプトの設定
k8s clusterリソースを操作 一時停止 タスクの一連の実行ステップを作成 タスクの依存関係を作成 Definitions Invocators -
72 実装例 apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: Name: sample-workflow spec:
entrypoint: main templates: - name: main steps: - - name: step1 template: whalesay - - name: step2 template: gen-random-int - name: whalesay container: image: docker/whalesay:latest command: [cowsay] args: ["step1"] - name: gen-random-int script: image: python:alpine3.6 command: [python] source: | import random i = random.randint(1, 100) print(i) ワークフローの開始テンプレートを指定 spec.entrypointは必須 テンプレートの実行順序 タスクの処理内容であるテンプレートの作成 -
77 Prefectの要素 ワークフロー定義.py Prefect Cloud Worker Deployment Storage Work Pool
・実行インフラ ・コード管理 ・スケジュール などの設定 docker S3 GCS Git kubernetes ECS Cloud Run ワークフロー実行 開発環境 管理画面 コード管理 実行環境 ワークフロー実行制御 LapTop -
78 実装例 from prefect import flow, task import pandas as
pd import s3_client @task def extract()-> pd.DataFrame: s3_client.download_file(S3_BUCKET, file_name) data = pd.read_csv(file_name) return data @task def transform(data: pd.DataFrame)-> pd.DataFrame: data_transformed = data.groupby('column') return data_transformed @task def load(data: pd.DataFrame): s3_client.upload(S3_BUCKET, file_name, data) @flow def etl(file_name: str): extracted_data = extract(file_name) transformed_data = transform(extracted_data) load(transformed_data) if __name__ == "__main__": etl(file_name=”sample.csv”) Task Task Task Flow Task = Python関数 Flow = 関数の依存関係 Task Flow Python関数に@taskデコレータをつけると Prefectはタスクとして認識する @flowデコレータでFlowとして認識する タスクの出力を次のタスクの入力にできる python workflow.py でCLI実行可能 -
79 GCP GKEでの実行例 ワークフロー定義.py Prefect Cloud Worker Deployment Kubernetes Work
Pool Kubernetes Job 開発環境 管理画面 コード管理 実行環境 GKE Artifact Registory prefect.yaml image自動ビルド -
80 実装例 name: flows prefect-version: 2.13.8 build: - prefect_docker.deployments.steps.build_docker_image: id:
build-image requires: prefect-docker>=0.4.0 image_name: "asia-docker.pkg.dev/{{ $GCP_PROJECT_ID }}/repository/auto-image" tag: latest dockerfile: auto platform: "linux/amd64" push: - prefect_docker.deployments.steps.push_docker_image: requires: prefect-docker>=0.4.0 image_name: "{{ build-image.image_name }}" tag: "{{ build-image.tag }}" pull: - prefect.deployments.steps.set_working_directory: directory: /opt/prefect/auto_image ワークフローのコード管理・実行インフラ環境・スケ ジュールなどの設定を prefect.yaml に記述 ワークフローのdocker imageをビルド 自作のDockerfileでビルドも可能 Container Registryにpush ワークフロー実行時の コード取得先の設定 -
81 実装例 definitions: tags: &common_tags - "gke" work_pool: &**common_work_pool** name:
"gke" job_variables: image: "{{ build-image.image }}" deployments: - name: "auto_image" tags: *common_tags schedule: - cron: "0 0 * * *" entrypoint: "flows/etl.py:etl" work_pool: *common_work_pool work poolの設定 実行したいインフラ環境 をここで変更 tag, scheduleなどを設定 -
87 Asset実装例 from dagster import asset from typing import Dict
import pandas as pd from sklearn.linear_model import LinearRegression @asset def iris_dataset() -> pd.DataFrame: return pd.read_csv( "https://docs.dagster.io/assets/iris.csv", names=["sepal_length_cm","sepal_width_cm","petal_length_cm","petal_width_cm","species"] ) @asset def logistic_regression_model(iris_dataset: pd.DataFrame) -> LinearRegression: x = iris_dataset[["sepal_length_cm", "sepal_width_cm", "petal_length_cm", "petal_width_cm"]] y = iris_dataset["species"].map({"Iris-setosa": 0, "Iris-versicolor": 1, "Iris-virginica": 2}) return LinearRegression().fit(x, y) @asset def accuracy(logistic_regression_model: LinearRegression) -> Dict: return { "intercept": logistic_regression_model.intercept_, "coef": logistic_regression_model.coef_, } @assetデコレータでAssetを 作成 関数引数がAssetの依存関係 を表す -
88 Asset Job実装例 from dagster import ( Definitions, load_assets_from_modules, define_asset_job,
AssetSelection, FilesystemIOManager, ScheduleDefinition, ) from . import assets all_assets = load_assets_from_modules([assets2]) iris_job = define_asset_job("etl_job", selection=AssetSelection.all()) schedule = ScheduleDefinition( job=iris_job, cron_schedule="0 0 * * *", ) io_manager = FilesystemIOManager(base_dir="data") defs = Definitions( assets=all_assets, schedules=[schedule], resources={"io_manager": io_manager}, ) assetの実行・監視を 行う集合 Asset Asset Asset Asset Job asset jobの作成 実行スケジュールの作成 job実行に関わる設定をまとめる -
90 Hybridの構成 Agent Code Location Deployment docker kubernetes ECS ワークフロー実行
開発環境 管理画面 コード管理 実行環境 Job実行制御 GitHub Actions Deployment main feature dagster_cloud.yaml -
dagster_cloud.yaml 91 AWS ECSでの実行例 Agent Code Location Deployment ECR ECS
ワークフロー実行 開発環境 管理画面 コード管理 実行環境 Job実行制御 ECS Service main 公式のGitHubテンプレート GitHub Actions 公式のCloud Formation -
92 code locationの設定 location_name: my_dagster_project image:{aws_account_id}.dkr.ecr.ap-northeast-1.amazonaws.com/dagster-image:latest code_source: package_name: my_dagster_project build:
directory: ./ registry:{aws_account_id}.dkr.ecr.ap-northeast-1.amazonaws.com/dagster-image:latest container_context: ecs: run_resources: cpu: "1024" memory: "2048" ECS Taskの起動image imageが自動buildされる ECS Taskのリソース設定 dagster_cloud.yaml Dagster Cloudに登録するcode locationの設定ファイル -
{ "StartAt": "RunCrawler", "States": { // 中略 "ETL": { "Type":
"Task", "Resource": "arn:aws:states:::glue:startJobRun.sync", "Parameters": { "JobName": "etlandpipeline" }, "Next": "StartTrainingJob" }, "StartTrainingJob": { "Type": "Task", "Resource": "arn:aws:lambda:us-east-1:547760918250:function:lambdaModelTrain", "ResultPath": "$", "Next": "CheckStatusTraining" }, "CheckStatusTraining": { "Type": "Task", "Resource": "arn:aws:lambda:us-east-1:547760918250:function:lambdaModelAwait", "ResultPath": "$", "Next": "CheckTrainingBranch" }, // 中略 } } 98 実装例(JSON) 実行するAWSリソースを指定 JSON形式のAmazonステートメント言語で ワークフローを記述 次の実行タスクの指定 -
6つのワークフローツールの特徴比較 Step Functions 特徴 シンプル 手軽 k8sと連携 Python DAG 活用事例が豊富
自然なPython 記法での開発 データ運用に特化 サーバレス AWSサービス ワークフロー 実装言語 digファイル (YAML) k8s manifest (YAML) Python (Operator) Python (Flow) Python (Job) GUI操作 JSON 利用形態 OSS OSS OSS SaaS クラウドマネージド OSS SaaS OSS SaaS クラウドマネージド 学習コスト 低 中 高 高 高 低 -
108 Redditの議論 Orchestration: Thoughts on Dagster, Airflow and Prefect? Dagster:
11 Prefect : 5 Airflow : 1 AirflowからDagster・Prefect・他ツールに移行した人が多い 好意的なコメント数 -
111 運用していたMLワークフロー N個のモデルの学習が毎日M回行われる データ取得 前処理 学習 オフライン評価 オンライン評価 データ分布評価 モデルデプロイ
データ取得 前処理 学習 オフライン評価 データ取得 前処理 学習 オフライン評価 ・・・ 並列 実行 でワークフローを定期実行 -
112 運用していたMLワークフロー ECS Taskでタスクを実行 データ取得 前処理 学習 オフライン評価 オンライン評価 データ分布評価
モデルデプロイ データ取得 前処理 学習 オフライン評価 データ取得 前処理 学習 オフライン評価 ・・・ ECS Task ECS Task ECS Task ECS Task でタスク実行を制御 -
117 なぜPrefectを選択した? 既存システムとの相性 リアルタイムログ監視 開発がしやすい ワークフローを柔軟に組める 低コスト タスクをECS Taskで実行できる Web
UIからログ追跡可能 Pythonで実装 if elseを使って書ける Prefect 2.0から値上がり😰 -
118 Prefect移行後のイメージ 118 オンライン評価 データ分布評価 モデルデプロイ データ取得 前処理 学習 オフライン評価
・・・ ECS Task ECS Task ECS Task ECS Task ・ワークフローツールだけ変える ・既存のアプリケーションコードは変えない 変える・変えない要素 -
123 参考文献 • A Brief History of Workflow Orchestration •
An Introduction to Workflow Orchestration • https://github.com/meirwah/awesome-workflow-engines • Data Orchestration: Definition, Parts, Examples, and Benefits • データエンジニアが最初に学ぶべき3つのポイント:「ETL」「データモデリング」「ワークフロー」 • [最終回] データパイプラインのためのワークフロー管理 • データパイプラインの管理 • Argo vs Airflow vs Prefect: How Are They Different • DigdagはなぜYAMLなのか? • 実践的データ基盤への処方箋〜 ビジネス価値創出のためのデータ・システム・ヒトのノウハウ • Orchestration: Thoughts on Dagster, Airflow and Prefect?