AWS Glueを使った Serverless ETL の実装パターン2020/07/03 · Amazon QuickSight...
Transcript of AWS Glueを使った Serverless ETL の実装パターン2020/07/03 · Amazon QuickSight...
-
AWS Glueを使ったServerless ETL の実装パターン
新井成一CX事業本部MADチーム
-
2自己紹介
CX事業本部MADチーム所属
サーバーサイドエンジニア
普段の業務API/IoT用のバックエンドの仕組みをAWSで構築&開発
データ分析&可視化する前のETL処理 ← ここ最近
-
3よくある話を少しする
AWS IoT Core Firehose S3
Amazon Athena
Amazon Redshift
Amazon EMR
Amazon QuickSight
Collection VisualizationAnalysis
-
4よくある話を少しする
AWS IoT Core Firehose S3
Amazon Athena
Amazon Redshift
Amazon EMR
Amazon QuickSight
Collection VisualizationAnalysis
時系列データを収集
分析処理ダッシュボードで可視化
-
5よくある話を少しする
AWS IoT Core Firehose S3
Amazon Athena
Amazon Redshift
Amazon EMR
Amazon QuickSight
Collection VisualizationAnalysis
時系列データを収集
分析処理ダッシュボードで可視化
そのままでは使えない場合が多い
データフォーマットがバラバラ非構造化/半構造化データなど
-
6
ETL処理が必要
-
7ETL処理が必要
AWS IoT Core Firehose S3
Amazon Athena
Amazon Redshift
Amazon EMR
Amazon QuickSight
Collection VisualizationAnalysis
時系列データを収集
分析処理ダッシュボードで可視化
LoadTransformExtract
-
8
『ETLで使えるAWSサービスは?』
-
9AWS ETL で検索すると
-
10
『なんか良さそう!』
-
11AWS Glueとは?
※ https://aws.amazon.com/jp/glue/から引用
AWS Glue は抽出、変換、ロード (ETL) を行う完全マネージド型のサービスで、お客様の分析用データの準備とロードを簡単にします。AWS マネジメントコンソールで数回クリックするだけで、ETL ジョブを作成および実行できます。AWS Glue では、AWS に保存されたデータを指定するだけで AWS Glue によるデータ検索が行われ、テーブル定義やスキーマなどの関連するメタデータが AWS Glue データカタログに保存されます。
https://aws.amazon.com/jp/glue/
-
12AWS Glue のコンソール画面
-
13
『なるほど、わからん...』
-
14今回する・しない話
今回する話AWS Glueの概要
AWS Glueを中心としたETL処理の実装方法
開発/テスト/デプロイ/モニタリング
今回しない話ETLやサーバーレスの概念の話
データ分析や可視化の手法の話
Amazon EMRやAWS Batchの話
-
15今回の発表の目的
「AWS Glueというサービスの概要がわかった!」
「AWS Glueでの実装イメージが湧いた!」
-
16INDEX
AWS Glueの概要 10min
AWS Glueに関連するサービスの話 5min
ETLの実装パターン 20min開発/テスト/デプロイ/モニタリング
-
17
AWS Glue の概要
-
18
『AWS Glue』よくわからん…
-
19なぜわからないのか?
1. 実態をつかみづらい
機能が多い
実は別のサービスの裏側で使われている
2. 何を指しているのかわからない問題
『Lambda』≒ Lambda Functionをイメージ
『Dynamo』≒ DynamoDBのテーブルをイメージ
『Glue』≒???
-
20
AWS Glueのメイン機能は2つ
-
21AWS Glueのメイン機能
AWS Glueのテーブルよく言われるデータカタログのこと
データのスキーマ情報(カラム名やデータ型)を持っている
データベース毎に管理する
AWS GlueのジョブETL処理の実行基盤
3種類から選択可能(Python Shell, Spark, Spark Streaming)
-
22テーブルとジョブのイメージ
-
23テーブルとジョブのイメージ
テーブル
-
24テーブルとジョブのイメージ
ジョブ
-
25
実演
-
26例えば
IoTデバイスからセンサーデータがJSON形式で送信されている
項目名やデータ型のなど分析基盤側で扱いづらい状態
AWS IoT Core Firehose S3
IoT
sensor
IoT
sensor
Amazon Redshift
E
• 保存されている生データを取得
T
• カラム名・データ型を変換
L
• 分析基盤へロード
ETL
-
27蓄積されているデータ
AWS IoT Core Firehose S3
IoT
sensor
IoT
sensor
[{"device_id": "A","timestamp": 1593007044,"location": {"lat": "35.698362","long": "139.773288"
}}
…
-
28蓄積されているデータ
AWS IoT Core Firehose S3
IoT
sensor
IoT
sensor
[{"device_id": "A","timestamp": 1593007044,"location": {"lat": "35.698362","long": "139.773288"
}}
…
項目名を変えたい
-
29蓄積されているデータ
AWS IoT Core Firehose S3
IoT
sensor
IoT
sensor
[{"device_id": "A","timestamp": 1593007044,"location": {"lat": "35.698362","long": "139.773288"
}}
…
データ型を変えたい
-
30テーブルの作成
S3
AWS glue data
catalog
Crawler
クローラーでテーブルを自動作成
-
31テーブルの作成
テーブルスキーマが登録される
S3
AWS glue data
catalog
Crawler
-
32ジョブの作成
Glueが自動生成してくれるスクリプトを利用
-
33ジョブの作成
データソースの指定 データターゲットの指定
※Redshit ClusterやGlue Connectionは事前に作成済
-
34ジョブの作成
データのマッピングを指定
-
35ジョブの作成
Glue Jobのスクリプトが自動生成される
-
36ジョブの実行
Redshiftにデータが投入される
-
37実演の振り返り
AWS IoT Core Firehose S3
IoT
sensor
IoT
sensor
Amazon Redshift
AWS glue data
catalog
CrawlerAWS IoT Core Firehose S3
IoT
sensor
IoT
sensor
Amazon RedshiftAWS Glue Job
ETL
-
38
イメージ湧きましたか?
-
39その他〜AWS Glueの機能〜
ワークフロー
ジョブやクローラの実行順序を定義できる
トリガー
ジョブやクローラーを起動タイミングを制御できる
スケジュール実行などが可能
開発エンドポイント
Glue Jobと同等の実行環境を用意してくれる
ジョブのスクリプトを開発するのに利用できる
-
40
AWS Glueに関連するサービスの話
-
41Glue JobとLambdaの比較
並列度を上げて処理したい場合はLambdaを検討すべき
※2020/06/04時点での東京リージョンでの比較
AWS Glue Job (Python Shell) AWS Glue Job (Spark) AWS Lambda
メモリ 1GB or 16GB 32GB - 128 - 3,008 MB
実行時間 デフォルトで48h デフォルトで48h 最大15min
同時実行数 アカウント内で50 アカウント内で50 リージョン毎に1,000
課金額 従量課金≒性能 * 実行時間(s)(ただし最小10分)
従量課金≒性能 * 実行時間(s)(ただし最小10分)
従量課金≒性能 * 実行時間(100ms)
起動のオーバーヘッド
数十秒 -数分 数十秒 -数分 数ミリ秒 -数秒
言語 Python Python or Scala Python, Node.js … など多数
-
AWS Step Functions workflow
42Glue Workflow と StepFunctionsの比較
多少難易度は高いが、StepFunctionのほうが柔軟
AWS Glue
Workflow
AWS Step
Functions
複雑さ 低 中
柔軟さ 低 高
連携先 少ない 多い
-
43実は裏側でGlueを使っているサービス
AthenaのCREATE TABLEはGlueのデータカタログを利用
-
44
実装パターンの紹介
-
45
これ以降
PySpark, Python Shell
を前提とした話になります
-
46実装の手順
開発 テスト デプロイ モニタリング
-
47開発とテスト
開発 テスト デプロイ モニタリング
-
48開発とテストのパターン
LocalStack
.py
AWS Cloud AWS Cloud AWS Cloud
AWS Glue
開発エンドポイントAWS Glue Job
.py
① ② ③ ④
AWS Services
-
49開発とテストのパターン
LocalStack
.py
AWS Cloud AWS Cloud AWS Cloud
AWS Glue
開発エンドポイントAWS Glue Job
.py
① ② ③ ④
AWS Services
実行環境がローカル
実行環境がAWS Glue
-
50開発とテストのパターン
実行環境がローカルなので、デバッグやテストがやりやすい
ジョブの実行時に発生する権限エラーやOMMなどには気づきにくい
Sparkを利用する場合は、実行環境を整
えるのが手間(バージョンの不一致やaws-glue-libsの既存の不具合などでハマ
りやすい)、ある程度のマシンスペックが必要
①のケースでは、モックツールで利用可能なAWSサービスが限られていたり、モックツール自体の不具合がある
LocalStack
.py
AWS Cloud
.py
① ②
AWS Services
-
51開発とテストのパターン
コードの実行環境がAWSなので、権限
やメモリ割り当て量が適切か確認しやすい
実行時間が計測しやすい
AWS利用費が高くなりがち
④のケースでは、ジョブの終了までか
なりの時間待たされるので、デバッグしずらい
AWS Cloud AWS Cloud
AWS Glue
開発エンドポイントAWS Glue Job
③ ④
-
52今回紹介するパターン
② ④
LocalStack
.py
AWS Cloud AWS Cloud AWS Cloud
AWS Glue
開発エンドポイントAWS Glue Job
.py
① ③
AWS Services
-
53
これ以降コードが出てきますが
分かりやすさ重視のため
不要な箇所は省略しています
-
54② AWSサービスを利用したローカル実行
AWS Cloud
.py
②
AWS Services
-
55②事前のセットアップ
※ https://docs.aws.amazon.com/ja_jp/glue/latest/dg/aws-glue-programming-etl-libraries.htmlを参照
Version
Python 3.6.9
aws-glue-libs glue-1.0
Apache Maven 3.6.0
Apache Spark 2.4.3
boto3 1.14.13
pytest 5.4.3
AWS Cloud
.py
②
AWS Services
※ aws-glue-libsの不具合: https://github.com/awslabs/aws-glue-libs/issues/25
https://docs.aws.amazon.com/ja_jp/glue/latest/dg/aws-glue-programming-etl-libraries.htmlhttps://github.com/awslabs/aws-glue-libs/issues/25
-
56②事前のセットアップ
AWS Cloud
.py
②
AWS Services
Dockerfileを作成するのもアリ
Version
Python 3.6.9
aws-glue-libs glue-1.0
Apache Maven 3.6.0
Apache Spark 2.4.3
boto3 1.14.13
pytest 5.4.3
-
57② aws-glue-libsにPytestが用意されている
Amazon Redshift
Spectrum
S3
AWS Cloud
$ git clone -b glue-1.0 --depth 1
https://github.com/awslabs/aws-glue-libs glue/aws-glue-libs
AWS glue data
catalog
CrawlerS3 AWS Glue Job
glue/aws-glue-libs/bin/
├── glue-setup.sh
├── gluepyspark
├── gluepytest
└── gluesparksubmit
.py
Pytestを利用する
-
テストコードを用意
58②簡単なテストコードを用意
import sysfrom src.pyspark.timeseries_etl import main_job
class TestClass(object):
def test_run_job(self):
# 引数を指定args = {
"--JOB_NAME": "timeseries_etl","--DB_NAME": "arai-test-
devio2020_database","--TBL_NAME": "timeseries_data","--OUTPUT_DEST": "s3://arai-test-
devio2020/pyspark-output",}sys.argv += [item for pair in args.items() fo
r item in pair]
# ジョブを起動main_job()
Amazon Redshift
Spectrum
S3
AWS Cloud
AWS glue data
catalog
CrawlerS3 AWS Glue Job
.py
-
ソースコード
59②簡単なソースコードを用意
def main_job():
# 引数取得args = getResolvedOptions(sys.argv, [
"JOB_NAME","DB_NAME","TBL_NAME","OUTPUT_DEST",
])
# セットアップsc = SparkContext()glueContext = GlueContext(sc)spark = glueContext.spark_sessionjob = Job(glueContext)job.init(args["JOB_NAME"], args)
# コミットjob.commit()
Amazon Redshift
Spectrum
S3
AWS Cloud
AWS glue data
catalog
CrawlerS3 AWS Glue Job
.py
-
Pytestを実行
60② pytestの実行
※ AWS のクレデンシャル情報をセットするのをお忘れなく
$ glue/aws-glue-libs/bin/gluepytest test/pyspark/test_timeseries_etl.pyAmazon Redshift
Spectrum
S3
AWS Cloud
AWS glue data
catalog
CrawlerS3 AWS Glue Job
.py
-
ソースコード
61②徐々に育てていく
# DynamicFrameの作成src_timeseries_dyf = glueContext.create_dynamic_f
rame.from_catalog(database=args["DB_NAME"],table_name=args["TBL_NAME"],transformation_ctx="src_timeseries_dyf"
)
# マッピングmapping_list = [
("device_id", "string", "device_id", "string"),
("timestamp", "int", "timestamp", "int"),("location.lat", "string", "latitude", "doubl
e"),("location.long", "string", "longitude", "dou
ble")]map_timeseries_dyf = ApplyMapping.apply(
frame=src_timeseries_dyf,mappings=mapping_list,transformation_ctx="timeseries_map_dyf"
)
Amazon Redshift
Spectrum
S3
AWS Cloud
AWS glue data
catalog
CrawlerS3 AWS Glue Job
.py
-
DataFrameへの変換
62② SparkのDataFrameも活用
# DataFrameに変換timeseries_df = map_timeseries_dyf.toDF()
# カラム追加timeseries_df = timeseries_df.withColumn(
"year", from_unixtime('timestamp', 'yyyy'))timeseries_df = timeseries_df.withColumn(
"month", from_unixtime('timestamp', 'MM'))
# 再パーティショニングtimeseries_df = timeseries_df.repartition('year',
'month', 'device_id')
# DataframeをDynamicFrameに変換timeseries_dyf = DynamicFrame.fromDF(
timeseries_df, glueContext, "timeseries_dyf")
Amazon Redshift
Spectrum
S3
AWS Cloud
AWS glue data
catalog
CrawlerS3 AWS Glue Job
.py
-
S3へ保存
63②テスト用のバケットに出力し中身をチェック
# 保存save_timeseries_dyf = glueContext.write_dynamic_f
rame.from_options(frame=timeseries_dyf,connection_type="s3",connection_options={
"path": args["OUTPUT_DEST"],"partitionKeys": [
"year","month","device_id"
]},format="parquet",transformation_ctx="save_timeseries_dyf"
)
Amazon Redshift
Spectrum
S3
AWS Cloud
AWS glue data
catalog
CrawlerS3 AWS Glue Job
.py
-
テストコード
64②テストの前後処理や結果のチェックを実装
def pytest_runtest_setup():print('¥n-----setup-----¥n')# テストデータの作成TEST_BUCKET.create()
…省略
def pytest_runtest_teardown():print('¥n-----teardown-----¥n')# テストデータの削除TEST_BUCKET.objects.all().delete()
…省略
def test_run_job(self):…省略
main()
# 結果の取得res_data = self.get_result_data()# 正解の取得corr_data = self.get_correct_data()
# 結果の確認assert res_data == corr_data
Amazon Redshift
Spectrum
S3
AWS Cloud
AWS glue data
catalog
CrawlerS3 AWS Glue Job
.py
-
launch.json
65②うまく設定すればデバッグ実行も可能
{"name": "PyTest Glue","type": "python","request": "launch","stopOnEntry": false,"pythonPath": "${command:python.interpreterPath}","module": "pytest",“args”: [“-svv”, "${file}", "--color", "yes"],"cwd": "${workspaceRoot}","env": {"PYTHONPATH": "${workspaceRoot}/glue/aws-glue-
libs:/usr/local/spark/python/lib/py4j-0.10.7-src.zip:/usr/local/spark/python/:${command:python.interpreterPath}",
"SPARK_CONF_DIR": "${workspaceRoot}/glue/aws-glue-libs/conf",
"AWS_SECRET_ACCESS_KEY": “","AWS_ACCESS_KEY_ID": "","AWS_SESSION_TOKEN": ""
},"console": "internalConsole","internalConsoleOptions": "openOnSessionStart“
}
Amazon Redshift
Spectrum
S3
AWS Cloud
AWS glue data
catalog
CrawlerS3 AWS Glue Job
.py
-
66② AWSサービスを利用したローカル実行
AWS Cloud
.py
②
AWS Services
-
67②事前のセットアップ
Version
Python 3.6.9
boto3 1.14.13
pytest 5.4.3
Pandas 0.25.1
AWS Cloud
.py
②
AWS Services
-
ソースコード
68② Pandasが便利
def main(plant_id_dpac, current_date):# 引数取得args = getResolvedOptions(sys.argv, [
"JOB_NAME","DB_NAME","TBL_NAME","OUTPUT_DEST",
])
# データの取得timeseries_list = get_timeseries_list()
# 該当データがなければ即終了if not timeseries_list:
logger.info("Timeseries data not found.")return
# pandasのDataframeに変換timeseries_df = pd.DataFrame(timeseries_list)
# TODO: 業務処理…省略
Amazon Redshift
Spectrum
S3
AWS Cloud
AWS glue data
catalog
CrawlerS3 AWS Glue Job
.py
-
69④ AWS Glue Job を直接実行して確認
AWS Cloud
AWS Glue Job
④
-
70④事前のセットアップ
AWS Cloud
AWS Glue Job
④
Version
Python 3.6.9
boto3 1.14.13
pytest 5.4.3
-
テストコード
71④ PytestでE2Eテストを実行
def test_exec_job(self, mocker):
# 引数をオーバーライドしてジョブを実行exec_res = glue_client.start_job_run(
JobName=pytest.JOB_NAME,Arguments={
"--DB_NAME": "arai-test-devio2020_database",
"--TBL_NAME": "timeseries_data","—-OUTPUT_DEST”: "s3://arai-test-
devio2020/pyspark-output"}
)
# ジョブの起動が成功していることを確認assert exec_res["ResponseMetadata"]["HTTPStatusCo
de"] == 200job_run_id = exec_res["JobRunId"]
Amazon Redshift
Spectrum
S3
AWS Cloud
AWS glue data
catalog
CrawlerS3 AWS Glue Job
-
テストコード
72④ Glue Jobが完了するのを待って結果の確認
…省略
# ジョブが完了するまで待つjob_status = wait_until_job_finished(pytest.JOB_N
AME, job_run_id, 300)
# ジョブが成功していることを確認assert job_status == "SUCCEEDED"
# テスト結果の取得df_test_res = self.get_result_by_dataframe()
# 結果の確認assert_frame_equal(df_test_res, df_corr_res)
Amazon Redshift
Spectrum
S3
AWS Cloud
AWS glue data
catalog
CrawlerS3 AWS Glue Job
-
73デプロイ
開発 テスト デプロイ モニタリング
-
74ソースコードと外部ライブラリのデプロイAWS Cloud
from setuptools import setup
setup(name="pandas",version="0.25.1",packages=[],install_requires=['pandas==0.25.1']
)
$ python setup.py bdist_wheel
S3
.py .whl
AWS Glue Job
参照
Upload
-
75AWS Glueリソースのデプロイ
AWS Glue JobAWS glue data
catalog
Crawler
AWS Cloud
# Glueresource "aws_glue_catalog_database" "database" {name = "${var.system_name}_database"
}
resource "aws_glue_crawler" "timeseries_crawler" {name = "${var.system_name}_timeseries_crawler"
database_name = aws_glue_catalog_database.database.namerole = aws_iam_role.glue_iam_role.arnschedule = "cron(0 */1 * * ? *)"table_prefix = "timeseries_"
s3_target {path = "s3://${var.system_name}/Data"
}}
resource "aws_glue_job" "timeseries_etl" {name = "${var.system_name}_timeseries_etl"command {script_location = "s3://${var.system_name}/glue-
script/pyspark/timeseries_etl.py"python_version = 3
}role_arn = aws_iam_role.glue_iam_role.arntimeout = 60max_capacity = 2glue_version = "1.0"default_arguments = {"--job-language" = "python""--enable-metrics" = "true""--extra-py-
files" = "s3://${var.system_name_prefix}-artifacts-store/glue/modules/pandas-0.25.1-py3-none-any.whl"
"--job-bookmark-option" = "job-bookmark-enable"…省略
-
76モニタリング
開発 テスト デプロイ モニタリング
-
77AWS Glue Jobでジョブメトリクスを有効化
CloudWatch Metrics
-
78アラート通知
AWS Glue Job Amazon CloudWatch
Events
Amazon Simple
Notification Service
AWS Lambda Amazon CloudWatch
Metrics
…省略"source": "aws.glue","detail-type": "Glue Job State Change","time": "2020-01-09T09:33:40Z","region": "ap-northeast-1","resources": [],"detail": {"jobName": "glue-job-for-err-notification","severity": "ERROR","state": "FAILED","jobRunId": "jr_a56a071553c6038a20f1578f74a013
6c94e1ea946a3e9516322b4b2bd2e3a5f4","message": "Command failed with exit code 1"
イベントソースの定義 受け取れるイベント
-
79Complete!
開発 テスト デプロイ モニタリング
-
80目的は達成できたか?
「AWS Glueというサービスの概要がわかった!」
「AWS Glueでの実装イメージが湧いた!」
-
81
ご清聴ありがとうございました