Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

AWSでAPI Gatewayから非同期でLambdaを起動してS3にファイルアップロードしようとしたらハマった話。

9,632 views

Published on

AWS Lambdaで色々とハマった話です。

Published in: Engineering
  • Be the first to comment

AWSでAPI Gatewayから非同期でLambdaを起動してS3にファイルアップロードしようとしたらハマった話。

  1. 1. AWS Lambdaで ハマった話。
  2. 2. 最近 • AWSをちょいちょいいじる • AWS Lambdaとやらに⼿を出す • 盛⼤にハマる • ある程度知⾒がたまった • いいタイミングでLTの機会が
  3. 3. Lambda? • ランバダ? • ラムダと読みます • 以下Lambda
  4. 4. Lambdaとは • コードをAWSクラウド上で実⾏してくれる • 対応⾔語はNodeJS,Java,Phython • AWSクラウド上の⾊々な所で実⾏トリガーを設定できる • 例えばS3へのファイルアップロード • DynamoDBのテーブル更新時(insert, update, …)
  5. 5. 例えば • S3に画像がアップロードされた瞬間、サムネイル 画像を⽣成する • S3にログファイルがアップされたら、即座にファ イルの解析を⾏う • DynamoDBにレコードがインサートされたら、何 かをする(利⽤シーン思いつかず)
  6. 6. デメリット • 300秒以上かかる処理はできない • メモリ1.5G以上使う処理はつらい • Javaが遅い(らしい)
  7. 7. メリット • EC2いらない • 安い • スケーラブル • 関数に対して割り当てるメモリを調節できる (128M ~1536M) • CPUはメモリ⽐例して勝⼿に強くなる
  8. 8. そして • 最近オンデマンド(https経由)からもLambdaを 起動できるようになった! • これは便利!
  9. 9. 何ができるのか • クライアント(ブラウザ)が直接Lambdaを起動で きる • Lambdaに対してGET, POST等でデータを送信でき る • そしてそのデータに応じて/対して⾊々とごにょご にょできる
  10. 10. ただし • HTTPS経由でのLambda関数の起動はAWS Lambda単体では実現できない • ので…
  11. 11. AWS API Gateway と、連携します
  12. 12. API Gatewayとは • LambdaをHTTPSで呼び出せるようにするやつ • これに関して詳細解説はしません • 詳細は公式へどうぞ • これとLambdaをうまく組み合わせて準備完了
  13. 13. で、何をしたいのか • ブラウザからポストしたデータをS3に書き出した い • けど書き出してる時間は待ちたくない • 要はポストするだけして即座に”200 OK”が欲しい • 厳密に⾔うと202
  14. 14. 理想のイメージ クライアント API Gateway Lambda とりあえず202 ⾮同期POST S3
  15. 15. まずは普通に やってみる。
  16. 16. • Node.jsのコードを記述 します • exports.handler = function() {}に渡され いるeventにPOSTされ たpayloadが⼊ってます • 普通にaws-sdkを使って S3にアップロードして るだけです
  17. 17. これを押すと関数のテストが出来ます
  18. 18. エンドポイントから叩いてみる ここから⾮同期化を⽬指す。 成功
  19. 19. ⾮同期化への道。
  20. 20. ⾮同期化へのアプローチ 1. 無思考的にsetTimeoutを試す 2. Node.jsのchild_processを使う 3. API Gatewayの統合リクエストヘッダーに
 X-Amz-Invocation-Typeを追加する 4. LambdaからLambdaを呼び出す
  21. 21. setTimeout(); • S3へのアップロード部分の 実⾏を遅延させてみる • setTimeout()は実⾏キュー への登録が遅延されるだけで 結局同⼀スレッドで実⾏され るので意味なし • (おさらい)Javascriptはシ ングルスレッド
  22. 22. ちなみに • setTimeout()後にプロセ スを強制終了してみる • プロセスが⼀瞬で終わり ます • 当然setTimeout内の処理 も実⾏されず。。
  23. 23. child_process • Node.jsはchild_processモジュールを通じて親プ ロセス(メインストリーム)から⼦プロセスを⽣成 することができます • ⼦プロセスは親プロセスから切り離す事ができる!
  24. 24. 何が嬉しいのか • ⼦プロセスを親から切り離すことによって、親プロ セスが死んでも⼦プロセスは動き続ける事ができる ようになる • 更にこの状態で⼦が親に対して、⾃分の処理終了を 待たないように宣⾔する事ができる • 通常は切り離したとしても親は⼦の終了を待つ
  25. 25. 実際のコード • spawnでOSコマンドを実 ⾏できる • detache: trueが切り離し 命令 • unref()することで⼦の終 了を待機しなくなる • これで勝ったと思いきや…
  26. 26. それ、Lambdaで 出来ないよ
  27. 27. なぜなのか • Lambdaではメインストリームの処理が終了した瞬 間、派⽣する処理は全て殺されます • なので前述の例で⾔うとunref()が実⾏された瞬 間、親プロセスは以降の⾏に処理が無いのでそこで 終了します • = ⼦も終了します
  28. 28. なので • こうしても同じです • Node.js的には正しいですが、 Lambda的には意図した動作になっ てくれません • detachしてるので⼦プロセスは⽣ き残れるはずですが、Lambdaでは process.exit()によって⼦も殺され ます • 無念。。。
  29. 29. X-Amz-Invocation-Type • Amazon API Gatewayの公式ドキュメントに下記 のような記述があります 要するに…
  30. 30. API Gatewayの ここの
  31. 31. これに これを 追加して下さい、ということです。
  32. 32. しかし • やってはみるものの、⼀向に⾮同期にならない • 10秒スリープするようなスクリプトを呼ぶと、ご丁 寧に10秒待たされる • API GatewayのLambdaに関連しそうなドキュメン トは⼀通り⽬を通したが⼀向に謎は解けない • ここでかなりハマる
  33. 33. いろいろ試す • メソッドリクエストから統合リクエストに対して ヘッダーをマッピングしなきゃいけない? • X-Amz-Invocation-Type?
 XAmzInvocationType?
 x-amz-invocation-type? • InvocationTypeはEvent?DryRun? • POST/GET?
  34. 34. 時は流れ • ふと初⼼に戻りLambdaの仕組みに⽴ち返る • Lambdaの公式ドキュメントに衝撃の事実を⾒つ ける
  35. 35. • LambdaはAPI Gatewayを⽤いたHTTPSを経由し て実⾏される場合、
 常にRequestResponse(同期)の呼び出しタイプ を使⽤します。
  36. 36. ん? • API Gateway側のドキュメントとLambda側のド キュメントで⽭盾が⽣じてる気がしなくもない • とはいえ出来ないものは出来ないので仕⽅ない • ということで最終⼿段
  37. 37. Lambda => Lambda • はい、LambdaからLambdaを呼びます
  38. 38. イメージ クライアント Gateway Lambda 200 OK ⾮同期 S3 Lambda
  39. 39. 実際のコード • Lambda上でaws-sdkを ⽤いたLambdaの⾮同期 呼び出しを⾏えばよいこ とに気づく • lambda.invokeAsync() がポイント • InvokeArgsには受け 取ったpayload(event) をそのままぶん投げる
  40. 40. ⾮同期化成功!
  41. 41. まとめ • Lambdaをうまく活⽤すればEC2いらずで経済的! • HTTPS経由の⾮同期呼び出しは⼯夫すれば何とか なる!
  42. 42. 最後に
  43. 43. ドキュメント読もう。
 ちゃんと。
  44. 44. ご清聴ありがとう
 ございました。

×