開発室ブログ

AWS

AWS Lambdaから高解像度のカスタムメトリクスを出力

ConoHaに引き続き、再びインフラ方面。今回はAWSで。

AWS上にシステムを開発する中で「とあるLambda関数の起動回数を監視して、スケールアウト/インする」って感じの機能が欲しいなー、と作り込んでいた時のメモです。

CloudWatchメトリクス(アラーム)の間隔

CloudWatchでは、アラームを作成して閾値5分間 に 関数が 5回 呼ばれたとか)を設定、それを超えたらAuto Scalingのアクションを発動! とかできます。ひとまず試しにLambda呼び出し回数のメトリクス(AWS/LambdaのInvocations)からアラームを作成してみると…なぜか監視間隔の10秒と30秒が選べないのが目に留まりました。

f:id:ajdev:20180110122037p:plain
表示はされてるけど、選択できない…

まぁ1分間隔でもいいんですが、今回の案件では極力早く検知 → スケールアウト開始したかったので、できれば使いたい。12回/60秒より、2回/10秒みたいな閾値のほうが細かく制御できそう…。で、調べてみると

  • メトリクスは、デフォルトでは1分間隔での取得
  • 1分未満のアラーム監視は高解像度(高分解能?)メトリクスを利用する

という2点がわかりました。

docs.aws.amazon.com

LambdaのNode.jsから高解像度メトリクスを出力する

標準で用意されているAWS/Lambda内のInvocationsを高解像度に設定すればいいの? とか考えて、調べるもよくわからず…(というか、そんな機能は存在しない?)
なので、対象のLambda関数から直接出力することにしました。単純に「適当な内容の高解像度メトリクスを投げる」という処理を追加しただけですが、起動回数がわかればいいのでこれで十分。

Lambdaのロール

CloudWatchにメトリクスを突っ込むので、Lambda関数のロールに "cloudwatch:PutMetricData" を追加してあげてください。反映には少し時間がかかるかもしれません(?)

"Statement": [
    {
        "Effect": "Allow",
        "Action": [
            "logs:CreateLogGroup",
            "logs:CreateLogStream",
            "logs:PutLogEvents",
            "cloudwatch:PutMetricData",
            .........
            .....
        ],
        "Resource": [
            "*"
        ]
    }
]

例えばこんな感じでしょうか。

Node.js(6.10)から高解像度でメトリクス出力

該当部分のコードはこんな感じです。ここを参考にしつつとりあえず。

Class: AWS.CloudWatch — AWS SDK for JavaScript

var AWS = require('aws-sdk');
.....
.....
.....
// 利用するCloudWatchのリージョンを設定します
AWS.config.region = event.region;
.....
.....
.....
// CloudWatchメトリクス設定
const params = {
  MetricData: [
    {
      MetricName: 'HiRes-Count',
      Dimensions: [
        {
          Name: 'DimName',
          Value: 'DimValue'
        },
      ],
      Timestamp: new Date(),
      Unit: 'Count/Second',
      Value: 1,
      // 高解像度指定
      StorageResolution: 1
    },
  ],
  Namespace: 'ACJP/Lambda'
};

// 実行
const cloudwatch = new AWS.CloudWatch();
cloudwatch.putMetricData(param, (err, data) => {
  if (err) {
    console.log(err, err.stack);  // an error occurred
  }
  else {
    console.log(data);  // successful response
  }
});
.....
.....
.....

秒単位で関数の実行回数が取れればいいので、適当に Unit = 'Count/Second' Value = 1 としています。ネームスペースやディメンション名はご自由に。
高解像度メトリクスにしたいので StorageResolution = 1 を忘れずに設定してあげます。

CloudWatchから確認

あとは適当に関数を実行して、メトリクスが出力されるのを待ちます。なんか、多少時間がかかったような気がします。
出力が成功していれば CloudWatch -> メトリクス から参照できます。

f:id:ajdev:20180110145617p:plain
ネームスペースが増えてるはず

これを使えば、10秒/30秒間隔のアラームも作成可能です。

f:id:ajdev:20180110152654p:plain

イエー(少しだけ料金かかりますが)

ひとまずできました。あとはスケーリングのアクションを指定すればOKですね。

今回は高解像度のほうが良いので作ってみましたが、普通は分単位でいい気がするし、細かくログとるだけならどっかに投げれば? って感じもあり、自分としてはあんまり使わなさそう…かなぁ。
秒オーダー(または独自項目)のメトリクスが欲しい! アラームで使いたい! ダッシュボードに並べたい! などなどの場合は、カスタムメトリクスを使ってみるといいかもしれません。

RecentPost