「AWS Black Belt Tech Webinar 2015 – AWS Lambda」レポート
こんにちは、虎塚です。
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/ディレクトリにファイルが残っていないかを確認して、残っていたら再利用するようにすれば、パフォーマンスアップが見込めるのでしょうか? いろいろ試してみようと思います、
それでは、また。