AWS re:Invent 2014で発表された新サービスAWS Lambda。 先日Limited Previewの申請が通ったので早速Lambda使って何かできないかと思い、Webサイトの監視をLambdaを使って実現してみました。
5分間隔で指定したサイトを監視し、400、500系のレスポンスが帰ってきた場合は、SNSに異常状態である旨メッセージ通知をします。
LambdaはS3上のファイルの変更やKinesisに届いたメッセージ、DynamoDBへのデータの更新といったイベントに反応して任意のコードを実行できるプラットフォームです。Lambda自体に定時処理を行うような仕組みは用意されていないので、Lambda Function内部でS3にオブジェクトをPUTすることでLambda Functionの実行をループします。
処理は↓のステップで行います。
- site-監視時刻ミリ秒(例:site-1418090313922)といった命名規則のファイルを用意し、以下のように監視したいURL記載しておきます。
12http://www.haw.co.jp/http://haws.haw.co.jp/ - S3に上記ファイルがPUTされたトリガーでLambda Functionを実行
- 対象ファイルの時刻をパースして監視時刻を出し、現在時刻より過去であればサイトチェック。現在時刻より未来であればまだ監視タイミングではないので対象のファイルのタイムスタンプを更新(2に戻る)。
- サイトチェックし400以上のステータスコードが帰ってきた場合は、SNSに通知。
- ファイル名に含まれる監視時刻を5分追加したファイル名でファイルを置き換え。
Lambdaの設定
新規にLambda Functionを作成します。Lambda Function Nameに任意のFunction名を入力し、Lamda Functionのコードを貼り付けます。(ライブラリを利用するケースは、ZIPアップロードも可能)
続いて、Lambda Functionに反応する関数名をHandler nameに定義し、このLambda Function実行時に与えるIAM Roleの設定します(今回はS3へのGET/PUT/DELETE権限と、SNSのPublish、CloudWatch Logsの権限を付加)。
最後に使用するメモリとタイムアウトの秒数を設定。
実際に設定したコードは↓。
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
var http = require('http'); var AWS = require('aws-sdk'); exports.handler = function(event, context) { var bucket = event.Records[0].s3.bucket.name; var key = event.Records[0].s3.object.key; console.log("bucket : " + bucket + ", key : " + key); var monitorTime = parseInt(key.split("-")[1]); var currentTime = new Date().getTime(); var s3 = new AWS.S3({region: 'us-west-2'}); if(monitorTime < currentTime) { s3.getObject({Bucket: bucket, Key: key}, function(err, data){ if(err) { console.log('error get object ' + key, err); context.done('error', err.stack); } else { var urls = data.Body.toString().split("\n"); for(var i=0; i<urls.length; i++) { var url = urls[i]; if(url) check(url); } console.log("create new timestamp"); var params = {Bucket: bucket, Key: 'site-' + (currentTime + 300000), CopySource: bucket + '/' + key}; s3.copyObject(params, function(err, dadta){ console.log("copy object done"); if(err) console.log(err); s3.deleteObject({Bucket: bucket, Key: key}, function(err, data){ console.log("delete object done"); if(err)console.log(err) context.done(null, ''); }); }); } }); } else{ s3.copyObject({Bucket: bucket, Key: key, CopySource: bucket + '/' + key, MetadataDirective: "REPLACE"}, function(err, data){ if(err) console.log(err) console.log('update timestamp'); context.done(null, ''); }); } }; function check(url) { console.log("check url : " + url); http.get(url, function (res) { console.log(url + " response:" + res.statusCode); if(res.statusCode >= 400) { notify(url, res.statusCode); } }).on('error', function(e){ console.log('error', e); notify(url, e); }); } function notify(url, status) { var sns = new AWS.SNS({region: 'ap-northeast-1'}); var params = { TopicArn: 'SNSのエンドポイント', Subject: 'Website Alert', Message: url + ' response bad status: ' + status }; sns.publish(params, function(err, data) { if(err) console.log(err, err.stack); else console.log(data) }) } |
Lambda Functionの作成が終わると、ダッシュボードでLambda Functionを選択して「Configure event source」を選択して、S3にファイルがPUTされた際にLambda Functionが実行されるよう対象のBucketの設定と、Lambda Functionを起動すめのInvocation Roleを作成/選択します。
※ ここで設定するBucketはLambda Functionと同じリージョンのBucketである必要があります。
実行状況
あとは、監視サイトを定義したファイルを対象のBucketにアップロードするとLambda Functionが起動します。Lambda Functionの実行ログはCloudWatch Logsに送信されているので、CloudWatch Logsのコンソールで↓のように確認できます。
またLambdaのダッシュボードでLambda Functionの実行状況が確認できます。
まとめ
Lambdaを利用することで、実行プラットフォームのことを意識する必要なくプログラムを動作させることができるのは大きなメリットだと感じます。いかにEC2を使わずにスケーラブルなプラットフォームを構築するか考える上で、とても魅力的な要素です。
個人的にはS3やKinesis、DynamoDBのトリガー以外にLambda自体が定期処理をサポートしてくれるといろいろ用途が広がって良いかと思います。Data Pipelineのスケジューラと組み合わせると、よりcronライクなトリガーになって面白いかも。(Data Pipelineのスケジュールの最小間隔は15分なのでそんなに細かい時間帯での設定はできませんが。)
またJavaScript以外にRubyサポートも!
Author Profile
- Twitter:@techmedia_think
Latest entries
2014.12.09AWS Lambdaを使ってサイト監視
2014.12.03Amazon Linuxでtd-agentをビルド
2014.11.23t1→t2への移行に伴い仮想化方式をPV→HVMにマイグレーション
2014.11.18CloudWatch Logsでアプリケーションサーバのログを収集