AWS Glueで経験したことのまとめ

こんにちは、足立です。僕のチームは、広告データをGlueで整形・計算したりしてます。
以前に記事を書いてからもう少しで1年経ちそうなので、
そろそろGlueを触って得た知識と経験を書いておこうかなと思います。

その前に以前書いた記事が、ちょっと酷い終わり方だったので追記しました。
blog.engineer.adways.net

本記事の内容

  • AWS Glueの料金計算方法
    • Glue Jobの設計失敗で料金が跳ね上がったお話
    • Glue Job料金が跳ね上がった解決策
    • AWS Glueの料金で気をつけること
  • 元ファイルのサイズによってエラーなるお話
    • 大きいファイル使用時にでるエラーについて
    • 小さいファイル使用時にでるエラーについて

AWS Glueの料金計算方法

1DPUの1時間あたり$0.44

Glue Jobが2DPUからしか動かせないので実質2DPU = $0.88(1時間)

10分で動かした時の料金計算方法が下記になります。

10(分) / 60 × 2(DPU) × $0.44 = $0.15

ちなみに10分以下だと10分に切り上げられて料金計算される仕様になっています。
なので、1分も9分も10分で計算します。
15分だと普通に15分で計算することになります。

※ カスタマーサポートにお世話になったので正しいはず

その料金認識が曖昧で起こった事件がこちら↓

Glue Jobの設計失敗で料金が跳ね上がったお話

料金が凄いことになった時のGlueのJob構成

オブジェクト指向的にやりたいこと毎にJobを分けて保守・管理を行なっていました。
手直しをしやすいように下記のような流れでJobを複数用意して自動で動かしていました。

f:id:AdwaysEngineerBlog:20180918214347j:plain

4つのJobは1つ辺り1~2分完了するJobで、料金計算だと40分で計算されます。
40(分) / 60 × 30(回数) × 2(DPU) × $0.44 × 30(月計算) = $528

Glue Job料金が跳ね上がった解決策

上記の件の解決策ですが、4つのJobを1つに纏めれば、
合計実行時間は約8分となるので、料金計算上10分になるので1/4となります。
オブジェクト指向的に考えて分割していた部分だがそもそもJobで分けるのではなく、
Pythonライブラリを作成してそこでクラス分ければ良いという考えになりました。

1日30回くらい動く処理だったので月額にすると
10(分) / 60 × 30(回数) × 2(DPU) × $0.44 × 30(月計算) = $132
40(分) / 60 × 30(回数) × 2(DPU) × $0.44 × 30(月計算) = $528
差額でいうと約$400近く無駄にしていたことになります。

AWS Glueの料金で気をつけること

  • Jobの実行時間を見て纏めた方が良さそうならまとめること。
  • ちゃんと料金仕様を把握すること。

元ファイルのサイズによってエラーなるお話

様々なエラーと戦ってきましたが、中でも苦戦したエラーの2つについて書こうと思います。
前提条件としてS3に置いているファイルをDynamicFrameにして読み込んでいることとします。

大きいファイル使用時にでるエラーについて

Diagnostics: Container [pid=○○,containerID=○○] is running beyond physical memory limits. Current usage: 5.7 GB of 5.5 GB physical memory used; 8.4 GB of 27.5 GB virtual memory used. Killing container.

上記のようなログが書き出されて物理メモリが一杯というエラーが出ていました。
普段ならパーティションで分散されているので困らない人は困らないと思うのですが、
計算処理をする際に.collect()で配列にする際にExecutorに分散されているものが
一度Driverに集められるという動きをするみたいで、その際に生じるエラーだと思っています。

ZeppelinだとSparkのoptionで設定できたのですが、

conf = SparkConf().set("spark.driver.memory", "8g")
sc = SparkContext(conf=conf)

AWS Glueだとoptionで変更出来ず、こちらで設定を出来ないみたいです。
なので、ファイルを分割して読み込むファイルサイズを小さくして動かしています。
この辺はEMR使うと良いそうです。

小さいファイル使用時にでるエラーについて

ValueError: Can not reduce() empty RDD
上記のエラーについて書いていこうと思います。

self.sc.parallelize(list, 200).toDF(sampleRatio=0.2)

このようにDataFrameをパーティション数設定して定義する際に、
実際の要素数が少な過ぎてパーティションで区切り過ぎているのが原因みたいでした。
大きいファイル用にパーティション数を定義してしまっていたのが原因で汎用的に切り替えるようにして解決しました。

最後に

自分がやって詰まったところ困ったところを簡単に記事にしましたが、
まだまだ色々書ける内容があるので、そのうちまた纏めたいと思います。