15分の壁を越えろ!GlueのPython shellでVPC Lambdaもどきの長時間ジョブを動かしてみた
こんにちは、平野です。
Lambdaが便利すぎて何でもLambdaで処理したい病になっているのですが、やはりタイムアウトが大敵です。 15分あるので、分割したりできる処理であればかなりのタスクがLambda関数に落とし込めるのですが、 分割しようもないタスクでは15分という壁は非常に高いものになってしまいます。
業務で、時々取得に15分以上も時間がかかるWebAPIへのアクセスというのがあったので、 今回はGlueのPython shellを使ってこの15分の壁を越えてみたいと思います。 (越えるというよりは、壁がない道を選んでるだけですけど...)
また、そのWebAPIへはアクセスできるIPに制限がかかっており、 特定のVPC内からでないとアクセスが届かないようになっていたので、 そのVPCの中でPython shellを起動してきちんとデータ取得ができるかも確かめてみました。
アクセス制限のない場合
まずは特にVPCに縛りがない場合です。
Python shellのジョブ作成を行っていきます。
TypeはPython shell
を選択します。
Pythonのバージョンは最新を選び、「ユーザーが作成する新しいスクリプト」を選択します。
次の「接続」の設定は、特に何も選択せずにスクリプトの作成に移ります。
スクリプトは以下のような、URLを叩いて結果を表示しつつS3にgzip保存するものを用意します。 解説するようなポイントはないのですが、むしろそれが大事で、 外部パッケージなどが必要になるとPython shellで利用するのはなかなか大変そう(まだやったことない)なので、 Python shellで標準で使用できるパッケージだけで利用できることは非常に重要です。
import boto3 import urllib.request import gzip try: url = "https://www.yahoo.co.jp" req = urllib.request.Request(url) with urllib.request.urlopen(req) as res: text = res.read() print(text.decode('utf8')) text_gz = gzip.compress(text) s3_client = boto3.client('s3') s3_client.put_object( Bucket="cm-hirano-debug-bucket", Key="test_output.gz", Body=text_gz) except Exception as e: print(str(e)) raise e
スクリプトを保存してジョブを実行すれば(パラメータ等の設定は不要)、 期待通りURLの中身が取得できました。
上記は数十秒程度で完了します(Python shellの起動にちょっと時間かかる)が、 Lambda関数ではないので、当然15分という縛りなどはありません。 Python shellのデフォルトのタイムアウト時間は......、2440分 = 48時間です!
VPC内での実行
次に、IP制限がかかっているなどの理由で、 特定のVPCからのみアクセス可能なURLに対してリクエストする場合を想定して、 目的のVPC内で実行するように設定を行います。
Glueの場合、Lambdaのように明示的にVPC内部でジョブを動かすという設定はありません。 しかしVPC内にあるRDSなどに接続する際には、指定したVPC内で動作するように設定が可能です。 なので、ダミーの接続情報を作成することで、VPC内Python shellを実現します。
なお、VPC、サブネットなどはすでに作成済みとします。
接続の作成
ダミーの接続を作成していきます。
接続名を適当に設定し、接続タイプはJDBCを選びます。
JDBC URLはダミーの適当なもので大丈夫ですが、バリデーションがあるので、
jdbc:protocol://host:0/databasename
のような文字列を入力しておきます。
ユーザ名、パスワードについても適当な文字列で大丈夫です。
VPCとサブネットは、ジョブを実行させたい目的のものを選択します。
また、セキュリティグループとしては、JDBC データストアに接続するための VPC の設定に記載されている通り、 自己参照のインバウンドルールを持つセキュリティグループを指定します。 以下のように、自分自身のセキュリティグループに対してインバウンドが全て開いたものを作成して設定します。
ジョブに接続を付与する
作成した「接続」をジョブに付与します。
S3のVPCエンドポイントの作成
最後にVPCからS3へ接続できるようにエンドポイントを作成します。
S3のサービスを選び、
エンドポイント作成先のVPCとルートテーブルを選択します。
実行
以上で設定は完了です。 これでジョブが目的のVPC内で実行されるようになりました。
スクリプト内のターゲットURLを変更して実行してみると、 実際に15分以上の処理が実行できていることが確認できました。 (Lambda関数じゃないので当たり前ですが)
※横長の画像を折り返して貼っています
料金
Lambda関数で実行した時との料金を比較してみます。
Lambdaのメモリは128MBとして、15分のジョブを実行した際の料金は以下のようになり、 Python shellを使った場合は4倍弱程度の料金となります。
Lambda AWS Lambda 料金
$0.0000002 + 0.0000166667 * 1/8(GB) * 900(秒) = $0.0018752
Glue Python shell AWS Glue の料金
$0.44 * 0.0625(DPU) * 1/4(時間) = $0.006875
※20191008現在での東京リージョンでの料金
※Lambdaは無料枠があります
まとめ
Lambda関数の15分制限に収まらないWebAPIへのアクセスを、GlueのPython shellを使って実現できました。 また、特定VPCからの接続に限定されているWebAPIへアクセスを行うため、ジョブが動くVPCの設定も行いましたが、 こちらも期待通りの挙動となり、無事15分の壁を超えてデータ取得をすることができました!
Python shellはLambda関数ほど柔軟性がなく色々制約もありますが、 ユースケースが合えば、実質タイムアウトなしのサーバレスPython実行環境として使うことができそうです! 他にも応用できる場面もあるかもしれませんので、機会があればまた挑戦してみたいです。
以上、誰かの参考になれば幸いです。