LoginSignup
3

More than 3 years have passed since last update.

New Relic初心者がNew RelicでLambdaを監視設定してみた。

Posted at

これはNew Relic Advent Calendar 2019の23日の記事です。


New Relic 初心者です。
今回、ちょっとNew Relicを触る機会がありまして、
よく使うAWSのサービスの1つであるAWS Lambdaの監視を試してみました。


基本的には、
サーバーレス機能の監視 » AWS Lambda監視 » 始めてみましょう AWS LambdaのNew Relic監視の概要
を実施したものになります。

準備

公式構成図

にある通り、CloudwatchのログをNew Relicに転送するためのLambdaを設定します。
有効化するスクリプトをダウンロードして、実行します。
https://github.com/newrelic/nr-lambda-onboarding/archive/master.zip

ちなみに、日本語ページだと、Python2.6.6が必須要件になってますが、
上記ファイルをダウンロードして実行すると、
Python3が必要と言われて、エラーになります。

こちらに関しては、英語ページの記載が正しいようです。
必須要件は Python 3.3 or higher
実行コマンドは pip3 install newrelic-lambda-cli

コマン実行の際、アカウントID、リンクするアカウント名、そのアカウントで発行するAPIキーが必要になりますので、
APIキーについては、アカウント設定画面(アカウントのドロップダウン -> Account settings -> Account -> Users and roles.)で発行しておきましょう。

Lambda準備

Node.jsで書くことが多い(9割ぐらいかな)ので、Serverless FrameworkとNewRelic謹製のLambda Layer追加を実施。

オプション#1:Serverless Frameworkプラグイン(Node.jsおよびPython)を使用してください
オプション#2: 当社のLambda Layer(Node.jsおよびPython)を手動で追加

ちなみに、
英語だと、「Option #3: Manually add our Lambda Layer (Node.js and Python)」 が増えてますね。

Step 2. Install instrumentation

Option #1: Use Serverless Framework plugin (Node.js and Python)
Option #2: Add Lambda Layer with our CLI (Node.js and Python)
Option #3: Manually add our Lambda Layer (Node.js and Python)
Option #4: Manually instrument Lambda code (all available languages)

自前でLambda Layerを作ってというケースは少ないような気がするので、なくても大丈夫そうです。

両方とも試してみましたが、最終的にはServerless Framworkで、謹製のLambda Layerを追加をする形に落ち着きました。

以下抜粋

service: new-relic-test-with-dynamodb

provider:
  name: aws
  runtime: nodejs12.x
  logs:
    restApi: true
  stage: dev
  region: ap-northeast-1

custom:
  defaultStage: dev
  newRelic:
    accountId: 1234567
functions:
  index:
    handler: newrelic-lambda-wrapper.handler
    environment:
      NEW_RELIC_ACCOUNT_ID: ${self:custom.newRelic.accountId}
      NEW_RELIC_LAMBDA_HANDLER: handler.index
    memorySize: 256
    timeout: 25
    layers:
      - arn:aws:lambda:ap-northeast-1:451483290750:layer:NewRelicNodeJS12X:3
    events:
      - http:
          method: any
          path: /api
          integration: lambda-proxy

最初ハンドラーの指定の意味がわかってなくて、ちゃんとドキュメント読め事案でした。
Layerで、ログを取得する対象のLambdaをラッパーしてるんですね。ふむふむ。

最後に、
「ステップ3。CloudWatchログを設定し、New Relic Lambdaへのストリーミングを行う」
をやるんですが、忘れて、データ来ないなーと思ったことが数回。すみません。

作ったLambda自体は、DynamoDBへの参照・更新を行う単純なものです。
Node.js v12.xランタイムで実行確認してます。
あ、エラー起きた時にどーなるか知りたかったので、乱数生成して、特定の数値の時に、異常終了するようにしてます。

'use strict';
console.log('Loading function...');

const AWS = require('aws-sdk');
const dynamo = new AWS.DynamoDB.DocumentClient({
  region: 'ap-northeast-1'
});
const Crypto = require('crypto');

const successMessage = 'Success!'
const failureMessage = 'Failure...'

module.exports.index = async (event, context) => {
  console.log('Received event:', JSON.stringify(event, null, 2));
  console.log('Received context:', JSON.stringify(context, null, 2));

  console.log('httpMethod :', event.httpMethod);
  let message;
  let results;
  const body = JSON.parse(event.body);

  const randomInt = Math.round(Math.random() * 100, 0);
  if ((randomInt % 5) === 0) {
    return randomInt / randomInt2;
  } else {
    switch (event.httpMethod) {
        case 'DELETE':
          const resDel = await deleteItem(body)
          if (resDel) {
            message = successMessage
          } else {
            message = failureMessage
          }
          break;
        case 'GET':
          const resGet = await getItem()
          if (resGet !== null) {
            results = resGet;
            message = successMessage
          } else {
            message = failureMessage
          }
          break;
        case 'POST':
          console.log('POST body :', body  );
          const resPost = await updateItem(body)
          if (resPost) {
            message = successMessage
          } else {
            message = failureMessage
          }
          break;
        case 'PUT':
          console.log('PUT body :', body  );
          const resPut = await insertItem(body)
          if (resPut) {
            message = successMessage
          } else {
            message = failureMessage
          }
          break;
        default:
          console.log(`Unsupported method "${event.httpMethod}"`);
    }
    const returnObj = {
      message,
      results,
    }
    const response = {
      statusCode: 200,
      body: JSON.stringify(
        returnObj,
        null,
        2
      ),
    };
    return response;
  }
};
async function getItem() {
  const params = {
    TableName: process.env['DYNAMO_DB_TABLE']
  }
  try {
    const result = await dynamo.scan(params).promise();
    console.log(result);
    return result["Items"];
  } catch (error) {
    console.error(error);
    return null;
  }
}
async function deleteItem(body) {
  const params = {
    TableName: process.env['DYNAMO_DB_TABLE'],
    Item: {
      'id' : body.id
    }
  }
  try {
    const result = await dynamo.delete(params).promise();
    console.log('deleteItem Success: ', result);
    return true;
  } catch (error) {
    console.error('deleteItem Error: ', error);
    return false;
  }
}
async function insertItem(body) {
  const params = {
    TableName: process.env['DYNAMO_DB_TABLE'],
    Item: {
      'id' : body.id,
      'name': body.name
    }
  }
  try {
    const result = await dynamo.put(params).promise();
    console.log('insertItem Success: ', result);
    return true;
  } catch (error) {
    console.error('insertItem Error: ', error);
    return false;
  }
}
async function updateItem(body) {
  const params = {
    TableName: process.env['DYNAMO_DB_TABLE'],
    Item: {
      'id' : body.id,
      'name': body.name
    }
  }
  try {
    const result = await dynamo.update(params).promise();
    console.log('updateItem Success: ', result);
    return true;
  } catch (error) {
    console.error('updateItem Error: ', error);
    return false;
  }
}

実行およびNew Relic上での確認

検証としては、Apache Benchで10並列1000リクエストのリクエストを投げています。画面サンプルはそれを2回投げた結果

https://one.newrelic.com/ でログインして、
Entity Explorer -> Lambda Functions -> 設定したLambda -> Summary を開きます。

2回ほどABでリクエスト投げた結果です。

NewRelic1
NewRelic2

そういえば、エラーレートが出てないんですけど、なんでかなーって感じです。
NewRelic3

メトリクス上は送られてきている(Summaryの下にあるCloudwatch Metricsで確認できます)ので、
計算式がおかしいか、もっとエラーが多くないとダメなのかもしれません。。。
NewRelic4
NewRelic5

細かいところまではみれていませんが、所感としては、
1つのLambdaについて、各種情報が数値、グラフ織り交ぜて、見れるのがいいですね。
個人的には、ColdStartが可視化されているのは評価高いです。
Cloudwatch Logsのログストリームをみれば、わかるんですが、
お、こんだけLambda起動したんか!っていうのがビジュアル的にわかるのは嬉しいです。
NewRelic6

そういえば、
「Provisioned Concurrency for Lambda Functions」を設定したLambdaだと、この辺どうなるんでしょうかね。検証できたらします。

今後

Lambdaのエラーの内容監視やDynamoDB自体の監視もできるようなんですが、
Infrastructureサブスクリプションの購入が必要なようなので、今度できたらやってみたいですね。
あと、通知って飛ばせるのかな?ってところまでみてないので、機会があればやってみたいところ

最後に

検証し始めてから、設定したAWSアカウントのCloudwatchの利用料金が上がっているのは、Datadogでも結構あがっていたので、
監視サービス使う上ではしょうがないでしょうかねと思う今日この頃。


初心者なりに頑張ってみましたが、
乱筆乱文のほど、どうぞお許しください。

また、ここ違うんじゃというご指摘お待ちしております。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3