Slide 1

Slide 1 text

AWS Glueを使った Serverless ETL の実装パターン 新井 成一 CX事業本部 MADチーム

Slide 2

Slide 2 text

2 自己紹介 CX事業本部 MADチーム所属 サーバーサイドエンジニア 普段の業務 API/IoT用のバックエンドの仕組みをAWSで構築&開発 データ分析&可視化する前のETL処理 ← ここ最近

Slide 3

Slide 3 text

3 よくある話を少しする AWS IoT Core Firehose S3 Amazon Athena Amazon Redshift Amazon EMR Amazon QuickSight Collection Visualization Analysis

Slide 4

Slide 4 text

4 よくある話を少しする AWS IoT Core Firehose S3 Amazon Athena Amazon Redshift Amazon EMR Amazon QuickSight Collection Visualization Analysis 時系列データ を収集 分析処理 ダッシュボード で可視化

Slide 5

Slide 5 text

5 よくある話を少しする AWS IoT Core Firehose S3 Amazon Athena Amazon Redshift Amazon EMR Amazon QuickSight Collection Visualization Analysis 時系列データ を収集 分析処理 ダッシュボード で可視化 そのままでは使えない場合が多い データフォーマットがバラバラ 非構造化/半構造化データなど

Slide 6

Slide 6 text

6 ETL処理が必要

Slide 7

Slide 7 text

7 ETL処理が必要 AWS IoT Core Firehose S3 Amazon Athena Amazon Redshift Amazon EMR Amazon QuickSight Collection Visualization Analysis 時系列データ を収集 分析処理 ダッシュボード で可視化 Load Transform Extract

Slide 8

Slide 8 text

8 『ETLで使えるAWSサービスは?』

Slide 9

Slide 9 text

9 AWS ETL で検索すると

Slide 10

Slide 10 text

10 『なんか良さそう!』

Slide 11

Slide 11 text

11 AWS Glueとは? ※ https://aws.amazon.com/jp/glue/ から引用 AWS Glue は抽出、変換、ロード (ETL) を行う完全マネージド型のサービスで、お 客様の分析用データの準備とロードを簡単にします。AWS マネジメントコンソール で数回クリックするだけで、ETL ジョブを作成および実行できます。AWS Glue で は、AWS に保存されたデータを指定するだけで AWS Glue によるデータ検索が行 われ、テーブル定義やスキーマなどの関連するメタデータが AWS Glue データカタ ログに保存されます。

Slide 12

Slide 12 text

12 AWS Glue のコンソール画面

Slide 13

Slide 13 text

13 『なるほど、わからん...』

Slide 14

Slide 14 text

14 今回する・しない話 今回する話 AWS Glueの概要 AWS Glueを中心としたETL処理の実装方法 開発/テスト/デプロイ/モニタリング 今回しない話 ETLやサーバーレスの概念の話 データ分析や可視化の手法の話 Amazon EMRやAWS Batchの話

Slide 15

Slide 15 text

15 今回の発表の目的 「AWS Glueというサービスの概要がわかった!」 「AWS Glueでの実装イメージが湧いた!」

Slide 16

Slide 16 text

16 INDEX AWS Glueの概要 10min AWS Glueに関連するサービスの話 5min ETLの実装パターン 20min 開発/テスト/デプロイ/モニタリング

Slide 17

Slide 17 text

17 AWS Glue の概要

Slide 18

Slide 18 text

18 『AWS Glue』よくわからん…

Slide 19

Slide 19 text

19 なぜわからないのか? 1. 実態をつかみづらい 機能が多い 実は別のサービスの裏側で使われている 2. 何を指しているのかわからない問題 『Lambda』 ≒ Lambda Functionをイメージ 『Dynamo』 ≒ DynamoDBのテーブルをイメージ 『Glue』 ≒ ???

Slide 20

Slide 20 text

20 AWS Glueのメイン機能は2つ

Slide 21

Slide 21 text

21 AWS Glueのメイン機能 AWS Glueのテーブル よく言われるデータカタログのこと データのスキーマ情報(カラム名やデータ型)を持っている データベース毎に管理する AWS Glueのジョブ ETL処理の実行基盤 3種類から選択可能(Python Shell, Spark, Spark Streaming)

Slide 22

Slide 22 text

22 テーブルとジョブのイメージ

Slide 23

Slide 23 text

23 テーブルとジョブのイメージ テーブル

Slide 24

Slide 24 text

24 テーブルとジョブのイメージ ジョブ

Slide 25

Slide 25 text

25 実演

Slide 26

Slide 26 text

26 例えば IoTデバイスからセンサーデータがJSON形式で送信されている 項目名やデータ型のなど分析基盤側で扱いづらい状態 AWS IoT Core Firehose S3 IoT sensor IoT sensor Amazon Redshift E • 保存されている生デー タを取得 T • カラム名・データ型を変 換 L • 分析基盤へロード ETL

Slide 27

Slide 27 text

27 蓄積されているデータ AWS IoT Core Firehose S3 IoT sensor IoT sensor [ { "device_id": "A", "timestamp": 1593007044, "location": { "lat": "35.698362", "long": "139.773288" } } …

Slide 28

Slide 28 text

28 蓄積されているデータ AWS IoT Core Firehose S3 IoT sensor IoT sensor [ { "device_id": "A", "timestamp": 1593007044, "location": { "lat": "35.698362", "long": "139.773288" } } … 項目名を変えたい

Slide 29

Slide 29 text

29 蓄積されているデータ AWS IoT Core Firehose S3 IoT sensor IoT sensor [ { "device_id": "A", "timestamp": 1593007044, "location": { "lat": "35.698362", "long": "139.773288" } } … データ型を変えたい

Slide 30

Slide 30 text

30 テーブルの作成 S3 AWS glue data catalog Crawler クローラーでテーブルを自動作成

Slide 31

Slide 31 text

31 テーブルの作成 テーブルスキーマが登録される S3 AWS glue data catalog Crawler

Slide 32

Slide 32 text

32 ジョブの作成 Glueが自動生成してくれるスクリプトを利用

Slide 33

Slide 33 text

33 ジョブの作成 データソースの指定 データターゲットの指定 ※Redshit ClusterやGlue Connectionは事前に作成済

Slide 34

Slide 34 text

34 ジョブの作成 データのマッピングを指定

Slide 35

Slide 35 text

35 ジョブの作成 Glue Jobのスクリプトが自動生成される

Slide 36

Slide 36 text

36 ジョブの実行 Redshiftにデータが投入される

Slide 37

Slide 37 text

37 実演の振り返り AWS IoT Core Firehose S3 IoT sensor IoT sensor Amazon Redshift AWS glue data catalog Crawler AWS IoT Core Firehose S3 IoT sensor IoT sensor Amazon Redshift AWS Glue Job ETL

Slide 38

Slide 38 text

38 イメージ湧きましたか?

Slide 39

Slide 39 text

39 その他 〜AWS Glueの機能〜 ワークフロー ジョブやクローラの実行順序を定義できる トリガー ジョブやクローラーを起動タイミングを制御できる スケジュール実行などが可能 開発エンドポイント Glue Jobと同等の実行環境を用意してくれる ジョブのスクリプトを開発するのに利用できる

Slide 40

Slide 40 text

40 AWS Glueに関連する サービスの話

Slide 41

Slide 41 text

41 Glue 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 … など多数

Slide 42

Slide 42 text

AWS Step Functions workflow 42 Glue Workflow と StepFunctionsの比較 多少難易度は高いが、StepFunctionのほうが柔軟 AWS Glue Workflow AWS Step Functions 複雑さ 低 中 柔軟さ 低 高 連携先 少ない 多い

Slide 43

Slide 43 text

43 実は裏側でGlueを使っているサービス AthenaのCREATE TABLEはGlueのデータカタログを利用

Slide 44

Slide 44 text

44 実装パターンの紹介

Slide 45

Slide 45 text

45 これ以降 PySpark, Python Shell を前提とした話になります

Slide 46

Slide 46 text

46 実装の手順 開発 テスト デプロイ モニタリング

Slide 47

Slide 47 text

47 開発とテスト 開発 テスト デプロイ モニタリング

Slide 48

Slide 48 text

48 開発とテストのパターン LocalStack .py AWS Cloud AWS Cloud AWS Cloud AWS Glue 開発エンドポイント AWS Glue Job .py ① ② ③ ④ AWS Services

Slide 49

Slide 49 text

49 開発とテストのパターン LocalStack .py AWS Cloud AWS Cloud AWS Cloud AWS Glue 開発エンドポイント AWS Glue Job .py ① ② ③ ④ AWS Services 実行環境が ローカル 実行環境が AWS Glue

Slide 50

Slide 50 text

50 開発とテストのパターン 実行環境がローカルなので、デバッグ やテストがやりやすい ジョブの実行時に発生する権限エラー やOMMなどには気づきにくい Sparkを利用する場合は、実行環境を整 えるのが手間(バージョンの不一致や aws-glue-libsの既存の不具合などでハマ りやすい)、ある程度のマシンスペッ クが必要 ①のケースでは、モックツールで利用 可能なAWSサービスが限られていたり、 モックツール自体の不具合がある LocalStack .py AWS Cloud .py ① ② AWS Services

Slide 51

Slide 51 text

51 開発とテストのパターン コードの実行環境がAWSなので、権限 やメモリ割り当て量が適切か確認しや すい 実行時間が計測しやすい AWS利用費が高くなりがち ④のケースでは、ジョブの終了までか なりの時間待たされるので、デバッグ しずらい AWS Cloud AWS Cloud AWS Glue 開発エンドポイント AWS Glue Job ③ ④

Slide 52

Slide 52 text

52 今回紹介するパターン ② ④ LocalStack .py AWS Cloud AWS Cloud AWS Cloud AWS Glue 開発エンドポイント AWS Glue Job .py ① ③ AWS Services

Slide 53

Slide 53 text

53 これ以降コードが出てきますが 分かりやすさ重視のため 不要な箇所は省略しています

Slide 54

Slide 54 text

54 ② AWSサービスを利用したローカル実行 AWS Cloud .py ② AWS Services

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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 Crawler S3 AWS Glue Job glue/aws-glue-libs/bin/ ├── glue-setup.sh ├── gluepyspark ├── gluepytest └── gluesparksubmit .py Pytestを利用する

Slide 58

Slide 58 text

テストコードを用意 58 ② 簡単なテストコードを用意 import sys from 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 Crawler S3 AWS Glue Job .py

Slide 59

Slide 59 text

ソースコード 59 ② 簡単なソースコードを用意 def main_job(): # 引数取得 args = getResolvedOptions(sys.argv, [ "JOB_NAME", "DB_NAME", "TBL_NAME", "OUTPUT_DEST", ]) # セットアップ sc = SparkContext() glueContext = GlueContext(sc) spark = glueContext.spark_session job = Job(glueContext) job.init(args["JOB_NAME"], args) # コミット job.commit() Amazon Redshift Spectrum S3 AWS Cloud AWS glue data catalog Crawler S3 AWS Glue Job .py

Slide 60

Slide 60 text

Pytestを実行 60 ② pytestの実行 ※ AWS のクレデンシャル情報をセットするのをお忘れなく $ glue/aws-glue-libs/bin/gluepytest test/pyspark/test_timeseries_etl.py Amazon Redshift Spectrum S3 AWS Cloud AWS glue data catalog Crawler S3 AWS Glue Job .py

Slide 61

Slide 61 text

ソースコード 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 Crawler S3 AWS Glue Job .py

Slide 62

Slide 62 text

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 Crawler S3 AWS Glue Job .py

Slide 63

Slide 63 text

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 Crawler S3 AWS Glue Job .py

Slide 64

Slide 64 text

テストコード 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 Crawler S3 AWS Glue Job .py

Slide 65

Slide 65 text

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.in terpreterPath}", "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 Crawler S3 AWS Glue Job .py

Slide 66

Slide 66 text

66 ② AWSサービスを利用したローカル実行 AWS Cloud .py ② AWS Services

Slide 67

Slide 67 text

67 ② 事前のセットアップ Version Python 3.6.9 boto3 1.14.13 pytest 5.4.3 Pandas 0.25.1 AWS Cloud .py ② AWS Services

Slide 68

Slide 68 text

ソースコード 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 Crawler S3 AWS Glue Job .py

Slide 69

Slide 69 text

69 ④ AWS Glue Job を直接実行して確認 AWS Cloud AWS Glue Job ④

Slide 70

Slide 70 text

70 ④ 事前のセットアップ AWS Cloud AWS Glue Job ④ Version Python 3.6.9 boto3 1.14.13 pytest 5.4.3

Slide 71

Slide 71 text

テストコード 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"] == 200 job_run_id = exec_res["JobRunId"] Amazon Redshift Spectrum S3 AWS Cloud AWS glue data catalog Crawler S3 AWS Glue Job

Slide 72

Slide 72 text

テストコード 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 Crawler S3 AWS Glue Job

Slide 73

Slide 73 text

73 デプロイ 開発 テスト デプロイ モニタリング

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

75 AWS Glueリソースのデプロイ AWS Glue Job AWS glue data catalog Crawler AWS Cloud # Glue resource "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.n ame role = aws_iam_role.glue_iam_role.arn schedule = "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.arn timeout = 60 max_capacity = 2 glue_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" …省略

Slide 76

Slide 76 text

76 モニタリング 開発 テスト デプロイ モニタリング

Slide 77

Slide 77 text

77 AWS Glue Jobでジョブメトリクスを有効化 CloudWatch Metrics

Slide 78

Slide 78 text

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" イベントソースの定義 受け取れるイベント

Slide 79

Slide 79 text

79 Complete! 開発 テスト デプロイ モニタリング

Slide 80

Slide 80 text

80 目的は達成できたか? 「AWS Glueというサービスの概要がわかった!」 「AWS Glueでの実装イメージが湧いた!」

Slide 81

Slide 81 text

81 ご清聴ありがとうございました

Slide 82

Slide 82 text

No content

Slide 83

Slide 83 text

セッション後はアンケートへのご協力をよろしくお願いします。 ご回答いただいた方には後日、資料を送付いたします。 SNS投稿にはこちらをお使いください。 #devio2020 イベントのポータルサイトはこちら https://classmethod.jp/m/devio_2020_connect/ ライブセッション録画もこちらから 視聴できます。 https://forms.gle/NzASFqrgcGyBFFzN7 15:00〜15:45 「AWS Glueを使った Serverless ETLの実装パターン」 のアンケートはこちらです。 Q&A Q&A