なからなLife

geekに憧れと敬意を抱きながら、SE、ITコンサル、商品企画、事業企画、管理会計、総務・情シス、再び受託でDB屋さんと流浪する人のブログです。

AWS Glueを扱ってみてツラかったところ。

冒頭から余談

しばらくブログの更新が空いてました。この期間、かなりしょっぱい仕事してました。まだ終わってないし、落ち着いてもいないけど、なんとなく書き残しておきたいネタになったので。


PySparkとかあんまり理解していない状況から、なんとなく「そのへんのETLツールと同じでしょ」ってノリで提案、受注してきてしまった案件に巻き込まれて触り始めたGlueですが、ツラかったところをツラツラ書きます。
「いや、そういうもんだろ」、って話もちょいちょいありますが。


コンセプトとしては素晴らしいし、すでにうまく活用できている現場もたくさんあるんだとおもいます。
多分、関わった案件の諸条件(要件とか、体制とか)と、マッチしてなかったんだと思います。


ていうか、プロジェクト自体ががうまく行ってたら、自分の中でももう少し良い印象が残り、その余韻で連載的にまとめようと思ってたんですけど、無理っす。
以下の記事に素晴らしいまとめがあるので、そちらに譲ります。
qiita.com


まあ、いわゆる愚痴です。ほどほどにお付き合いください。
「Glue」と検索して「つらい」ってサジェストされるまで連呼するつもりはないので。

RDBMSに対するUpdateがない。

RDBMSに対してInsert(mode=append)かDrop/Create/Insert(mode=overwrite)しかできないです。
ん?overwriteってそういう動きかーい、っていう。

MySQL相手でも、Insert into ... Duplicate key updateが使えないです。


Update相当のことをするには、Out先のデータもGlueの中に読み込んで、新規に取り込むデータとマージして、対象テーブルへのTruncate&Insertで取り込むことになります。
そうでなければ、RDBMS側に毎回新規に取り込むだけのワークテーブルと、本来Updateしたい本体テーブルと2段階で作成しておいて、GlueでワークテーブルにInsertして、RDBMSの中でワークから本体テーブルにSQLでUpdateをかけます。

RDBMSからの取り出しは、常に全件。

RDBMS上で絞り込んだあとのデータを取り出すのではなく、まずテーブルのデータをすべてGlue=Sparkの世界に持ってきてから、Sparkの機能をでフィルタリングを行って対象レコードを絞り込みます。
結果、RDBMS上はフルスキャンかかるし、Glue側はメモリを大量に使うし、その間のトラフィックも大量発生するし。


いや、SELECTに限らず、任意のSQLを飛ばす手段もあるにはあるんですよ。ベタなPythonコードを書いてDBにコネクション張ってSQLを投げるようにコードを書く手段が。ただ、そんなことをするくらいなら、Glue/PySparkじゃなくて普通にPythonで書けばいいじゃない、っていう。

レコードレベルのデータ加工が辛い

これは私のPySparkに対する知識のなさかもしれませんが、やろうとすると、PySparkでのコード作業量が一気に増える。
しかも、Glueのドキュメントでは全然足りなくて、Apache Spark/PySparkのドキュメントを見るしかなくなるんだけど、またこれを読み解くのも結構難解。
ていうかGlueのDynamicFrameではなく、SparkのDataFrameに変換してからの話になるので、DynamicFrameの良さ(速さ)が吹っ飛ぶんだよね。


結局、RDBMSに無加工で取り込んでから、SQLで加工しました。慣れた技術でやるのが一番早い。

取り扱える文字コードがUTF8だけ。

個人的にはUTF以外のファイルを扱いたくもないけど、UTF8以外を扱いたいニーズは山程あるわけで。

CSV読み書きのオプションが弱い。

quoteCharつけても全部の列にquoteされないし。バグ?

Glue Catalog側でヘッダありなしのオプションつけても、ヘッダ無し出力できないし。

Glueが自動生成するPySparkの中で
glueContext.write_dynamic_frame.from_catalogだと、細かいオプション指定できないし。
glueContext.write_dynamic_frame.from_optionsだと、細かいオプション指定できるからヘッダ無し出力はできるかもしれないけど、かわりにData Catalogに定義した内容、意味なくなって、出力先をハードコードしなきゃいけないし。


さすがにエスケープなしの改行混じりデータを読み取れというのは酷か。そんなCSVファイルを送りつけてくるほうが悪い。

ファイル出力時、デフォルトだと大量のファイルに分散出力される。

そもそもが分散処理が前提だから仕方ないけど。


で、GlueのDynamicFrameのままではRepartitionできなくて、一旦SparkのDataFarmeに変換してあげなきゃいけない。
「DynamicFrame.toDF().repartition(1)」して、そのままDataFrameからWriteする(出力先に指定等にDataCatalog使えないからハードコードする)か、fromDF()でDynamicFrameに戻してからWriteするか。


DataFrameのままWriteしようとすると、modeが「error or errorifexists」になっていて、追加も置き換えもできないので、モード変更も追加しなきゃいけないし。

ファイル出力時、任意の名前にできない。

処理結果のファイルを使った後続処理がGlue以外で実装する必要があるときに、ファイル名を固定できないから、取ってくるファイルの判定のためのロジックとか余計に書かなきゃいけないし。




オブジェクトのコピーができない。

似たようなものを作るニーズって絶対あるし、「バックアップをとっておいて、いじってうまくいったら、古いの消そう」とかいうのにも対応してない。
PySparkスクリプトはS3上に保存されるし、CodeEditorで中身をまるごとコピーしてテキストで何処かに保存しておけばなんとかなるけど、Data Catalog側はそれもできない。

オマケに、CLIでDescribe(Glueのコマンドだと「get-ほげほげ」)もCreateも当然サポートしてるんだけど、そのgetで取れるJSONが、そのままCreateに食わせてもエラーになるという残念仕様なので、開発->検証->本番用の移行とか、結局同じ設定作業の繰り返し。最初からGUI使わずにコードで全部組んでおけば良いんだろうけど、Glueって、「ほとんどGUIから」ってのがウリだったはずで。



起動のオーバーヘッドが大きい

「裏でEMRが動いているLambda」とイメージすれば理解はしやすいですが、現実問題としてつらい。
実際、ログを見るとEMR(のコード)が動いてます。


一発目のジョブを起動するのに、10分位かかります。何分放置すると眠ってしまうのかは測っていませんが、連続実行ならすぐ動きます。


「起動オーバーヘッドは大きいが、大量処理は速い」という、このサービスの特徴そのものなのですが、少量データでデバッグしているときがつらい。
走らせて、エラーが出て、考えて、直して、リランする。その間に裏で動くインスタンスはオネム


実行時間1分以内、でも起動に10分、とか、かなり泣けてきます。
Eclipseでローカルビルドに10分かかるような重いマシンで作業しているような感覚。


もしかして、開発エンドポイントを立てて、「Apache Zeppelin」を使えば解決する話?
Zeppelinをイチから覚えている余裕もなかったんで。
流石にGlueの公式資料にZeppelinの話はほとんど載ってないし。




Management Consoleが全体的に辛い。

一覧画面の操作性が不統一。

一覧のソートができたりできなかったり。フィルタがうまく効いたり効かなかったり。
オブジェクト数が増えると軽く死ねる。

最初、日本語表示が機能してなかったんだけど、日本語表示が機能するようになってからは、ソートができる画面でソートさせると描画か固まる(Loadingから進まない)とか。


・・・やっと直したっぽい。
これは英語表示に切り替えればそもそも発生しないので、結局英語で使っているのだけど、他の「普通に日本語で使えているサービスの画面」も英語になってしまうから、クッソ不便でした。


あと、表示列幅も変更できない。割と長いオブジェクト名になりがちなので、ほぼ見切れる。
OnMouseでフルネームがポップアップするんだけど、これがまた誤操作(クリックすると1コ上とか1コ下をクリックした扱いになる)を誘発してウザい。


CrawlerからTablesを作るときの、テーブル名の命名が柔軟性がない自動生成のみ。

必然的にオブジェクト名が長くなる。
カラムタイプをCSVのデータの中身から推定して作ってくれるのはありがたいんだけど。


じゃあ、しかたない、手動でつくるか、、、

Glue Catalogのテーブル定義、手動ではS3対象しか作れない。

RDBMSのTablesも、手動で作りたいやん。
Crawlerから作ると、「任意のPrefix+スキーマ名+テーブル名」なので、かなり長くなる。そして一覧から見切れる。



オブジェクトの情報の更新が制限される

オブジェクト名の修正ができないとか、一部属性が変更できないとか。

さらに、Glue CatalogのTablesで、S3上のファイルを定義するのにS3 Pathを更新できないの。。。




GlueJobの作成ウィザードが弱い

DataのSourceとTargetを指定して、カラムマッピングするGUIが提供されるんだけど、カラムの表示順序がぐっちゃぐちゃで大混乱。
それでも、SourceとTargetで列名を揃えておくと、自動で対応関係をマップしてくれるからそのときはラクだけど、列名バラバラのときは、自動マップもクッソ適当。

PySparkのコードに落としてからだと、このGUIによるマップの再表示もできないから、修正は常にコード上。
マッピング処理するコードが1行で異常に長いので、これを直すのも結構苦痛。


たぶん、向いているユースケースじゃなかったんだ

と思うことにした。

とにかくGlueが自動生成するPySparkのコードに極力手を加えない、という使い方で。
PySparkを手足のように使える人じゃないと、Glueの良さは引き出せないんじゃないか?

逆に、どんなのが向いていそうか、って考えた。

RDBMSCSVから、JSONApache Parquetへの変換に利用するケース(TargetがRDBMSではなくS3)に向いているかなと。いわゆる「S3をデータレイクとして」っていう、最近流行りの文脈。

S3上にファイルを置いて、それを直接アクセスして分析を行う、Athena/S3 Select/EMR(EMRFS)/Redshift Spectrumを利用する際には、parquetとかの方が速いだろうし、適切なサイズで分割されていたほうがよいでしょう。そのための前処理には扱いやすそう。


今の仕事でそのへんを使うケースは、そうそう無さそうなんだけど。



Sparkの勉強をするいい機会になったし、Sparkの環境構築の手間は省けるし、いい本にも巡り会えたけど、Glue自体は、ワリとツラい経験でした。

アプリケーションエンジニアのためのApache Spark入門

アプリケーションエンジニアのためのApache Spark入門


AWSサポートには大変お世話になりました。

一時期、毎回同じ担当の方がずっと対応してくれたのですが、非常に細かく検証して返答をしてくれ、かなり助かりました。


外資系サービス企業のサポート窓口に問い合わせて、こんな真摯な対応をしてもらったのは始めてです。
最近はその時の担当の方に当たららず、回答も微妙なものが増えてきてる感もありますが、AWSサポートに対してはトータルでは好印象です。
今後も頼らせていただきます。