
「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を導入する場合
- LambdaがサポートするAMI(前述)を利用して、EC2インスタンスを起動する
 - OSアップデートをおこない、必要なツール、ライブラリ、Node.jsをインストールする
 - 必要なネイティブライブラリをダウンロードする
 - スタティックライブラリ用に設定する
 - モジュールのビルドとインストールをおこなう
 - npmでパッケージをインストールする
- PKG_CONFIG_PATHでコンパイルしたバージョンのOpenCVを指定して、ライブラリをコンパイルする
 
 - 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/ディレクトリにファイルが残っていないかを確認して、残っていたら再利用するようにすれば、パフォーマンスアップが見込めるのでしょうか? いろいろ試してみようと思います、
それでは、また。







