AWS Lambda メモリ容量による処理性能の違い
はじめまして。
CTCのクラウドイノベーションセンターで、クラウドを活用した開発やシステムアーキテクチャの検討を行っている丸山です。
第1回目の投稿は、AWS Lambdaの処理性能について調査した結果について書いてみたいと思います。
AWS Lambdaとは
LambdaとはAWSが提供しているコンピュートサービスの1つで、イベントをきっかけとして、登録したコードを実行させることができます。”イベントをきっかけ”にして処理が走りますので、常時起動しているサーバが不要になるのが特徴です。
2016年2月9日現在対応しているイベントとランタイムを調べてみました。
※各イベントについては別の機会に解説したいと思います。
【イベント】
- S3
- DynamoDB
- Kinesis
- SNS
- SES
- Cognito Sync Trigger
- CloudWatch Logs
- CloudWatch Events
- CloudWatch Events – Schedule
- CloudFormation
- AWS IoT
【ランタイム】
- Node.js
- Java
- Python 2.7
Lambdaでコードを実行するまで
ユーザがLambdaにより処理を行うために必要なステップは以下の5つです。
- ランタイムを選ぶ
- コードを書く
- Lambdaに割り当てる権限を設定する
- メモリ容量を設定する
- タイムアウト時間を設定する
上記のステップ2以外は選択するだけですので、時間がかかることはありません。
このように”本来やりたい処理”の作成にだけに時間を使えるのがLambdaを使うメリットの1つではないかと思います。
また、何らかのリクエストによりLambdaが起動するように設定しておけば、リクエスト数に応じてスケールしていくので、アクセス数が予測できないような場合にも有効です。(そもそもリクエストが無ければ課金されませんので、お得です!)
利用料金に関しては、公式のアナウンスを参考にしていただければと思いますが、非常に安価にコードを実行することができます。
また、毎月無償利用枠が設定されており(永久に有効らしいです)、ちょっとした検証作業や小規模アプリケーションで利用する場合には、無償枠内で収めることもできるかもしれません。
Lambdaのメモリ容量と処理能力の関係
コードを登録するだけで利用可能なLambdaですが、割り当てるMemory容量はどのように決定するのでしょうか?
私は当初、Lambdaを実行した際に使用されたメモリ容量で決定していました。
実行時に使用されたメモリはLambdaの管理コンソールまたはCloudWatch Logsから確認することができます。
- Lambdaの管理コンソールで確認
- CloudWatch Logsで確認
上記の処理では Max Memory Usedが35MBとなっており、128MBで充分足りているのでしばらく128MBの設定のまま利用していました。
しかし、もっと処理速度が速くならないかな?と思い、調査してみると、公式ドキュメントに以下の記載がありました。
Lambda 関数のコンピューティングリソース
Lambda 関数の作成時に、関数に割り当てたいメモリ量のみを選択します。次に、AWS Lambda は M3 タイプなど、汎用 Amazon EC2 インスタンスタイプと同じ割合を使用して、メモリに比例した CPU 能力を割り当てます。たとえば、256 MB を Lambda 関数に割り当てる場合、128 MB を割り当てた場合よりも 2 倍の CPU 共有が割り当てられます。
※AWS Lambda開発者ガイドより引用
書かれている通り、割り当てるメモリ容量により処理速度が違ってくるようです。
どの程度違うのか気になったので、実際に測定してみました。
実行するコードはDynamoDBに保存された1000件のアイテムをscanする処理としました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
console.log('*** Loading Lambda Func ***'); var AWS = require('aws-sdk'); var dynamo = new AWS.DynamoDB.DocumentClient({region: 'ap-northeast-1'}); var TABLE_NAME = 'SpecTest'; function scanTable(context) { var params = { TableName: TABLE_NAME }; console.log('start: ' + context.getRemainingTimeInMillis()); dynamo.scan(params, function(err, res) { if (err) { console.log(err, err.stack); context.succeed('*** scan fail ***'); } else { console.log('end: ' + context.getRemainingTimeInMillis()); console.log('scan count: ' + res.Count); context.succeed('*** scan complete ! ***'); } }); } exports.handler = function(event, context) { scanTable(context); }; |
コード説明
- 4行目:AWS SDK for JavaScript の DynamoDB DocumentClientを使っています。
- 12, 18行目:context.getRemainingTimeInMillis()でLambdaがTimeoutするまでの残り時間が取得できます。
- 16行目:context.failとしてしまうと、Lambdaによりコードが再実行されてしまうため、context.succeedとし、”Lambdaの処理が完了した”という扱いにしています。
計測は3回実施し、その平均を取っています。
グラフからわかるように、処理時間(Duration)が割り当てメモリ容量に半比例していることが分かります。
したがって、”処理時間を短くしたい”という要件がある場合には、実際に使用されるメモリ容量を参考にするのではなく、大きなメモリ容量を割り当てるのが正解のようです。
料金面から考えてみると、Lambdaは100ms毎の課金のため、今回の場合768MB以上の割り当てでは全て200msの課金がされることになります。
同じ課金時間であれば、メモリ容量が増えることに比例して料金が増えていきますので、今回の場合では768MBが妥当な設定であるかと思います。
Memoryを1536MBを割り当て1回処理を実行した際の課金でも約$0.000025のため、大きな差とはなりませんし、そもそも検証であれば無償利用範囲で利用することもできますが、余計なリソースは割り当てないようにしたいですね。
以上、Lambdaの割り当てメモリによる処理速度比較でした。
処理速度を向上したい場合は、割り当てメモリ容量をチェックしてみましょう!