「AWS Black Belt Tech Webinar 2015 – AWS Lambda」レポート

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、虎塚です。

1月21日(水)の夕方に実施された「AWS Black Belt Tech Webinar 2015 - AWS Lambda」を聴講したので、レポートします。講師は、アマゾンデータサービスジャパンの西谷さんです。

今回は解説内容と資料がほぼ対応されていたので、後ほど公開される資料をご覧いただければ、どんなセミナーだったかが手に取るように分かるかと思います。(資料は次のページで公開予定とのことです)

……が、社内チャットで昨日ちょうどLambdaの話題が出ていたので、資料が公開されるまでの数日間に参考になればと思い、レポートをアップしておきます。

Lambda

Lambdaが解決する問題

世の中の課題はシンプル。たとえば、「S3バケットに画像が保存されたらサムネイルを作りたい」、「DynamoDBに保存される値が意図した形式かチェックしたい」など。

しかし解決方法は複雑で、たとえば前者の課題に対して次のような作業が必要になる。

  • アップロード検知のためのサーバと仕組みの準備
  • イベント駆動処理のためのサーバと仕組みの準備
  • OSや処理系の構築、それらのバージョンアップ
  • リクエストが多い場合に、スケール、耐障害性を高める構成
  • キャパシティや状態、セキュリティの24時間モニタリング

AWS Lambdaとは

イベントをトリガーにコードを稼動させるサービス。

インフラの管理がいらない
EC2やOSの管理作業から解放されて、エンジニアがビジネスロジックに集中できる
コードをアップロードするだけで、Lambdaがキャパシティ、スケール、デプロイ、耐障害性、モニタリング、セキュリティパッチ適用をハンドリングしてくれる
オートスケール
イベントのレートに合うように、数件/日〜数千件/秒までLambdaが自動的にスケールする
プロビジョニング中や完了などの状態を気にせずデプロイできる
スケールしても、実際にコードが稼動した分だけの支払いでよい
Bring your own code
ユーザがNode.jsで書いたコードを実行する
コード内では、スレッド/プロセス生成、バッチスクリプトや実行ファイルの実行、/tmpディレクトリへのread/writeができる
各種ネイティブライブラリも、コードと一緒にアップロードすると使える
細やかな料金体系
コードが稼動した時間(コンピュート時間)に対する100ミリ秒単位での従量課金
リクエストに対する低額の課金

Lambdaは、2014年11月に発表され、2015年1月21日時点でPreviewとして提供されている。

ユースケース

Lambdaを利用した次のような機能が考えられる。

イメージのリサイズ、サムネイル生成
S3への画像アップロードに応じて、サムネイル生成やリサイズを実行する
値チェックや別テーブルへのコピー
DynamoDBへの書き込みに応じて、値チェックをしつつ、別テーブルの更新やプッシュ通知を実行する
監査と通知
S3へのCloudTrailログ保管に応じて、内容を分析し、異常を検知したらプッシュ通知を実行する

上のような機能を組み合わせることで、次のようなサービスが考えられる。

クチコミアプリ
投稿の書き込みや表示はDynamoDBに直接接続して行う
レート計算は、モバイルアプリから直接Lambdaを実行して、非同期で実行する
写真共有モバイルアプリ
モバイルアプリからS3に画像を直接アップロードし、アップロードイベントをトリガーにLambdaファンクションを起動させる
画像をリサイズして、メタデータをDynamoDBに登録し、結果をSNSへ送り、プッシュ通知する

従来サーバサイドで実行していた処理をLambdaに任せることで、バックエンドのサーバを排して実現できるのがポイント。

Lambdaファンクション

  • JavaScript (Node.js) で記述する
  • zip形式でアップロードする、もしくはManagement Consoleのインラインエディタで直接記述する
    • zipファイルに各種ライブラリを含めることができる
  • メモリ容量: デフォルト128MB、64MB単位
  • 実行時間のタイムアウト: デフォルト3秒、1秒単位、最大60秒
  • Lambdaファンクションの起動と実行にそれぞれIAM Roleを設定する
  • /tmpにread/write可能
  • 各ファンクションは隔離されたコンテナ内で実行される

ネイティブライブラリ

Lambdaファンクション内で利用するライブラリを、独自にビルドしてパッケージングできる。

これにはNode.jsをインストールしたAmazon Linuxと同等のマシンが必要になる。Amazon Linuxに含まれるライブラリを使ってビルドする必要があるため。

そこで、ドキュメント(AWS Lambda: How it Works - AWS Lambda)の「Supported Versions」に記載されている「Public Amazon Linux AMI version」のAMIからEC2を起動し、それを利用してビルドするとよい。

ライブラリは、スタティックにコンパイルするか、ダイナミックリンクを指定してコンパイルする。

(例)OpenCVを導入する場合

  1. LambdaがサポートするAMI(前述)を利用して、EC2インスタンスを起動する
  2. OSアップデートをおこない、必要なツール、ライブラリ、Node.jsをインストールする
  3. 必要なネイティブライブラリをダウンロードする
  4. スタティックライブラリ用に設定する
  5. モジュールのビルドとインストールをおこなう
  6. npmでパッケージをインストールする
    • PKG_CONFIG_PATHでコンパイルしたバージョンのOpenCVを指定して、ライブラリをコンパイルする
  7. Lambdaファンクションのコードとともにzipファイルにして、アップロードする

コンテナのライフサイクル

開始

  • ファンクション作成時、もしくは、コードや設定を更新した後の初回実行時に、新たにコンテナが作成される
  • コンテナ作成時に、ファンクション用のコードがコンテナにロードされる
  • Node.jsでは、ハンドラが最初に呼び出される前に、コンテナ作成ごとに1回だけ初期化コードが呼び出される

終了

Timeout
ユーザが指定した実行時間を超えた場合、実行中の処理内容にかかわらず、即時停止される
Controlled termination
コールバッックの1つがcontext.done()を呼び出して終了した場合、他のコールバックの実行状況にかかわらず停止する
Default termination
すべてのコールバックが終了してファンクションが終了した場合。
(注意)このケースでも、下記で説明するprocess.exit()を呼び出した時と同じように、ログに「Process exited before completing request」と出力される
クラッシュ、もしくはprocess.exit()の呼び出し
不具合のあるライブラリがセグメンテーションフォールドを起こした場合
ログには「Process exited before completing request」と出力される

再利用

実行からある程度時間が経過した後に、ファンクションを再度実行する場合は、新たにコンテナが作成される。しかし、コードの変更がなく、前回の実行からあまり時間が立っていない場合は、以前のコンテナが再利用されることがある。

コンテナが再利用されると、初期化処理がスキップされるので、パフォーマンス上有利。また、前回の処理で/tmpに書き込んだ内容が残っている。

ただし、再利用についての細かい条件は公開されていない。また、再利用されるかどうかをユーザがコントロールできないので、再利用を前提とした実装はNG

プロセスの凍結と再開

ファンクション終了時にバックグラウンドプロセスがあると、Lambdaはプロセスをfreezeさせ、次回ファンクションを呼び出した時に再開する。

これは、コンテナが再利用された場合だけおこなわれるため、実行が保証されない。また、バックグラウンドプロセスが残っていても、再利用開始までの間に処理はおこなわれない。

AWS Lambdaの使い方

コード

基本事項
Node.jsで記述する
AWS SDKとImageMagickライブラリは組込み済みのため、ライブラリとして同梱しなくてもrequireするだけで使える
ステートレスに実装する
データの永続化には、S3、DynamoDB、その他インターネット経由で利用できる外部のDBを利用する
Lambdaファンクションが実行されるサーバは毎回異なり、直接ログインできない
その他
プロセス/スレッド、/tmp領域、ソケットが使える
各種ライブラリが使える
インバウンドのソケット接続はできない(Lambdaファンクションが外部からの接続を受け付けることはできない

プログラミングモデル

  • exportsする関数名が、Lambdaが呼び出す関数名になる
    • ファンクション作成時、コードのアップロード時に指定する
  • イベントデータをパラメータとして渡す
    • JSON形式
    • 構成はサービスごとに異なる
    • カスタムイベントの場合、InvokeAsync発行時の引数として渡した値
  • 終了時にはcontext.done()を呼ぶ
    • 明示的に処理を終了するために必要(呼び出し忘れると、必要以上に長い時間実行されうる)
    • 第1引数: 成功時はnull、値が入っているとエラーとなる。null以外は文字列化されて、CloudWatchのログに記録され、リトライされることがある
    • 第2引数(オプション): メッセージ文字列。テスト実行時に画面下部のログに表示される。成功/失敗時どちらも使える

(※コード例は発表資料を参照ください)

IAM Roleでコード実行用のテンポラリのクレデンシャルが発行される。

Lambdaファンクションの作成

作成方法は2つある。

Management Console組込みのエディタを使う
サンプルテンプレートがあり、簡単にはじめられる
zipファイルをアップロードする
ライブラリを含める場合はこちら
ディレクトリを含まない形でまとめる必要がある(コードのあるディレクトリでzip -r foo.zip等)。ディレクトリを含めると、イベントハンドラーが見つからないというエラーになる
リソースサイズの設定
メモリサイズ: 128MB〜1GBの間で、64MBごとに設定する
タイムアウト: 1〜60秒の間で設定する(デフォルトは3秒)
イベントソースの設定
イベントソースとは、ファンクションのトリガー元のこと
2015年1月21日現時点では、S3バケット、DynamoDB Stream、Kinesis Streamを設定できる(DynamoDB Streamはプレビュー)
CLIではaws lambda add-event-soutceを実行する

イベント

イベントは、JSON形式でLambdaに渡される。Lambdaファンクションはイベントごとに実行される。

PUSHモデル: S3とカスタムイベント
順不同
サービスもしくはアプリケーションがInvokeAsyncを呼んで直接実行
3回までリトライ
PULLモデル: DynamoDBとKinesis
順序性あり(Streamに入ってきた順)
イベントリソースに設定したStreamに対して、Lambdaが取得しにいく
データが期限切れになるまでリトライ

モニタリング

CloudWatchで、Lambdaファンクションのリクエスト数、エラー数、レイテンシといったメトリクスを監視できる。

デバッグ

  • Lambdaファンクションの実行ログがCloudWatchに出力される
  • 実行開始/終了と消費リソースについてのログ項目として、メモリ使用量、実行時間、課金対象時間がある
  • カスタムログ項目も追加できる

Lambdaファンクション作成時の注意事項

ロールを正しくセットアップする
Execution roles: Lambdaファンクションができることを決定
Invocation roles: 誰がファンクションを実行できるかを決定
再帰処理は慎重に
イベントハンドラ内でS3やDynamonoDBへ書き込むと、別のイベントがトリガーされて、無限ループになることがある

リミット

/tmp領域の容量(512MB)や、プロセス数(1024)、スレッド数(1024)、1リクエストあたりの実行時間(60秒)などの制限がある。

料金体系

リクエスト数と実行時間(100ms単位)にそれぞれ課金される。関数に割り当てたメモリ容量によって単価が異なる。

参考資料

Q&A

Q. LambdaからRDSも使えますか?
A. できますが、VPCで接続できません。RDS側でインターネット側からのアクセスを許可する必要があります
Q. /tmpの記録内容は一定時間で削除されますか?
A. コンテナを終了するタイミングで削除されます。Lambdaは最大でも60秒しか実行できないので、データを長期間保存するのには向きません。
Q. PULLモデルの方が高いですか?
A. PULL、PUSHでLambdaの料金に違いはありません
Q. Management ConsoleのRoleの設定画面で、Roleが1つしか設定できないようなのですが
A. 設定画面は別々の場所にあります。Execution Roleの設定は、Lambdaのコードのすぐ近く。Invoke Roleの設定は、S3のイベントソースの方に存在します。
Q. Node.js以外の言語への対応予定はありませんか?
A. あります。ただし、時期や対応言語は不明です。
Q. 課金は、リクエストと実行時間のそれぞれに対しておこなわれますか?
A. Yes.
Q. 東京リージョンでいつ使えるようになりますか? プレビューが取れるのはいつですか?
A. アナウンスできる情報はありません
Q. 他のサービスにLambdaからアクセスする際、IPアドレスを固定できませんか?
A. 今はできません。要望は多いです。
Q. 無限ループを回避するベストプラクティスはあるでしょうか?
A. インプットとアウトプットのS3バケットを分ける設計がおすすめです
Q. イベント発行とLambdaのリージョンは同一でないとダメですか?
A. Yes. たとえば、Lambdaを設定したのがus-eastなら、S3バケットも同じリージョンに作成します。
Q. 処理の途中でコンテナがダウンすることはありますか?
A. 意図せずプロセスが異常終了することはありえます。ファンクションから例外が発生してcatchしていない場合、最終的にプロセスが終了します。これはNode.jsの仕様です。
Q. 無限ループしたらどうなりますか?
A. ループし続けますw

感想

夢が広がるLambdaがテーマということで、Q&Aも盛りだくさんでしたね。早く東京リージョンでも使えるようになるといいですね!

今回のウェビナーでは、特にコンテナの再利用と、プロセスの凍結と再開についてのお話が面白かったです。

tmp/ディレクトリにアクセスする処理をする場合、tmp/ディレクトリにファイルが残っていないかを確認して、残っていたら再利用するようにすれば、パフォーマンスアップが見込めるのでしょうか? いろいろ試してみようと思います、

それでは、また。