Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

AWS X-RayをServerless Frameworkで簡単構築・可視化まで

こんにちは!エンジニア3年目、フロントエンド&AWSサーバーレス系エンジニアを目指し勉強中のmiuraです。

サーバーレス構成だと簡単に立ち上げられる一方で、ある程度の開発規模になってくると非同期に連携したり、複数のサービスが関係したりするので、
エラーになった際にどこで失敗しているのか、デバッグしていくのが大変になることがありませんか?
または、レンスポンスが遅いと感じるがどのAWSサービスが起因して遅くなっているか確認するのが大変だと思ったことがありませんか?

そこで活躍するのがAWS X-Rayです。
AWS X-Rayはトレース対象であるサービスのリクエスト・レスポンス情報を収集するサービスで、
AWSコンソールにて収集した結果をマップ形式で見ることができ、各サービスの実行時間をグラフで可視化することができます。

今回はサーバーレスアプリへのX-Rayの適用を、Serverless Frameworkを用いて簡単に追加し、AWS上で可視化するところまでを紹介します。

全体構成

f:id:acro-engineer:20180318152127p:plain:w600

全体構成図中の①、②に分けて話をします。
API GatewayからAWS Lambdaの実行
 AWS LambdaがAPI Gatewayをトリガーとして実行されていることを可視化してみます。

AWS LambdaからAWS SNSやDynamoDBの呼び出し
 ①で作成したAWS LambdaからAWS SNSを呼び出し、AWS SNSをトリガーに実行されるAWS LambdaにてDynamoDBの操作が行われていることを可視化してみます。

ツール/ライブラリ

ツールとライブラリは以下のものを使います。

  • サーバーレス
名前 バージョン
Serverless Framework 1.20.2
AWS SDK for JavaScript 2.176.0
AWS X-Ray SDK for Node.js 1.1.6
serverless-plugin-tracing 2.0.0


  • 開発
名前 バージョン
Python 3.6
AWS X-Ray SDK for Python 0.96

API GatewayからAWS Lambdaの実行

以前使用したServerless Frameworkを今回も使います。

まずはPython3系用のサンプルプロジェクトを作成します。

serverless create --template aws-python3 --path aws-x-ray-serverless
cd aws-x-ray-serverless

次に、Serverless FrameworkのX-Rayプラグインをインストールし、serverless.ymlにAWS X-Rayを有効にする設定と
API Gatewayの設定を行います。

npm install aws-sdk aws-xray-sdk serverless-plugin-tracing

aws-x-ray-serverless/serverless.yml

service: aws-x-ray-serverless

plugins:
  - serverless-plugin-tracing # トレース有効用のプラグイン

provider:
  name: aws
  runtime: python3.6
  region: us-west-2
  apiKeys:
    - aws-x-ray-serverless-api-key
  tracing: true # X-Rayでのトレースを有効にする
  iamRoleStatements:
    - Effect: Allow
      Action:
        - xray:PutTraceSegments # X-Rayにセグメントドキュメントをアップロードする権限を付与する
        - xray:PutTelemetryRecords # X-Rayにテレメトリをアップロードする権限を付与する
      Resource: "*"

functions:
  hello:
    handler: handler.hello
    events:
     - http: # API Gatewayの設定
        path: hello
        method: get
        private: true

以上で、AWS X-RayおよびAPI Gatewayの設定ができました!
このようにプラグインをインストールし、serverless.ymlにたった数行設定を書くだけでX-Rayを適用することが出来ます。

早速、AWSにデプロイをしましょう。

sls deploy

デプロイが完了したら、curlコマンドやRestClientなどでAPI Gatewayを呼び出してLambdaを実行させます。

curl -s 【API GatewayのURl】 -H "x-api-key:【APIキー】"

すると、実行結果をAWSコンソールのX-Rayのサービスにて見ることが出来ます。

f:id:acro-engineer:20180318175904p:plain:w800

緑色の円が表示されていることからLambdaの実行は成功したことが分かります。
5xxエラーや4xxエラーなどがある場合、赤色や黄色で表示してくれるのでひと目でどこに問題があるかを確認できます。
中央の数字はそのサービスでの平均レスポンス時間と 1 分間に送信したトレース数を表しており、どこで処理に時間が掛かっているのかなども確認することが出来ます。

本格的なプロダクトともなると、多くのLambdaを互いに呼び出す形で作ることになります。
その際にどこでエラーになっているかを上図のようなサービスマップで簡単に確認できるのは、私のような開発者にとっては嬉しい機能ですよね。

また、円グラフをクリックすればさらに詳細なトレース情報を見ることが可能です。
トレースについては次の構成での結果で説明します。

AWS LambdaからAWS SNSやDynamoDBの呼び出し

①でClient、API Gatewayを通してLambdaを実行する流れをAWS X-Rayで表示しました。
そこで次に、①の続きとしてAWS LambdaからAWS SNSやDynamoDBを呼び出して、それをAWS X-Rayで表示してみましょう。

まずは、AWS LambdaでのAWS SNSDynamo DBの呼び出しをトレースをするためにPythonAWS X-Ray SDKをインストールします。

pip install aws-xray-sdk -t .

次に自動生成したhandler.pyとserverless.ymlの一部を編集します。

aws-x-ray-serverless/handler.py

# -*- coding: utf-8 -*-
import json
import boto3

# AWS X-Rayのライブラリを読み込み
from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.core import patch_all

# AWS X-Rayのパッチを適用
patch_all()


def hello(event, context):
    body = {
        "message": "Go Serverless v1.0! Your function executed successfully!",
        "input": event
    }

    # AWS SNSを呼び出し
    sns = boto3.client('sns')
    try:
        sns.publish(
            TopicArn="arn:aws:sns:us-west-2:471043657237:hello",
            Subject=body['message'],
            Message=json.dumps(body['input'])
        )
    except Exception:
        raise

    response = {
        "statusCode": 200,
        "body": json.dumps(body)
    }

    return response


# AWS SNSで受け取った情報をDynamoDBに保存するLambdaスクリプト
def put_hello(event, context):
    sns = event['Records'][0]['Sns']

    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table('hello_log')

    try:
        table.put_item(
            Item={
                "timestamp": sns['Timestamp'],
                "id": sns['MessageId'],
                "subject": sns['Subject'],
                "message": sns['Message']
            })

    except Exception:
        raise

aws-x-ray-serverless/serverless.yml

provider:
  name: aws
  runtime: python3.6
  region: us-west-2
  apiKeys:
    - aws-x-ray-serverless-api-key
  tracing: true
  iamRoleStatements:
    - Effect: Allow
      Action:
        - xray:PutTraceSegments
        - xray:PutTelemetryRecords
        - sns:Publish # AWS SNSをPublishする権限を追加
        - dynamodb:PutItem # DynamoDBのテーブルにItemをPutする権限を追加
      Resource: "*"

functions:
  hello:
    ...

  # AWS SNSをトリガーに実行されるLambdaを追加
  putHello:
    handler: handler.put_hello
    events:
     - sns: hello

# DynamoDBのテーブルを追加
resources:
  Resources:
    helloLogTable:
      Type: 'AWS::DynamoDB::Table'
      Properties:
        TableName: hello_log
        AttributeDefinitions:
          - AttributeName: timestamp
            AttributeType: S
        KeySchema:
          - AttributeName: timestamp
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 2
          WriteCapacityUnits: 1

気づきましたでしょうか?
AWS LambdaでのAWS SNSDynamo DBの呼び出しをトレースすると聞くといろいろな設定が必要そうと感じますが、
実際にX-Rayの適用として追加で記述したのは、

  • patch_all()

だけ。
これだけでAWS SNSDynamo DBを呼び出すboto3などのライブラリにX-Ray用のパッチが適用されてトレースが出来るようになります。
この手軽さは正直異常ですね(^^;

実際に再度デプロイコマンドを実行して、curlコマンドやRestClientなどでAPI Gatewayを呼び出してみます。

sls deploy
curl -s 【API GatewayのURl】 -H "x-api-key:【APIキー】"

結果、AWSコンソールのX-RayのサービスにてAWS SNSやDynamoDBへのフローも表示されるようになりました。
Service Mapの下段にあるClientはAPI Gatewayを通してAWS Lambda、そしてAWS SNSを呼び出しており、次のトリガーとなっています。
上段のClientがそのAWS SNSから呼び出されたことを表しており、AWS Lambdaを通してDynamo DBにエラーなくアクセスしていることが分かります。

f:id:acro-engineer:20180501175611p:plain:w800

そして、赤い枠にあるような円グラフをクリックするとサービスの所要時間をヒストグラムで確認することができます。
これにより、レスポンスとしては正常な200ステータスとなっているが、異様に時間が掛かっている場合がないかを確認することが出来ます。

f:id:acro-engineer:20180709075033p:plain:w800

さらに、Tracesの詳細を見ることでクライアント呼び出しからレスポンスまでの流れをタイムラインで見ることが出来ます。
上記で異様に時間が掛かっている場合の原因が、DynamoDBの呼び出しで時間が掛かっているのかそれ以外なのかをこれで調査することが出来ます。

f:id:acro-engineer:20180709075836p:plain:w800

実際に、Lambdaのレスポンスが異常に遅いことが発覚し調査を行った際、Tracesの詳細を見ることでDynamoDBの呼び出しに時間が掛かっていることが分かったことがありました。
その時の原因としては、あるDynamoDBのテーブルがいろんなところから呼び出されており、設定していたスループットを超過して制限が掛かっていたことが判明しました。
こういったこともX-Rayを見れば簡単に調査することが魅力的ですね。

まとめ

どうでしたでしょうか。
今回みたいに簡単な準備と実装だけでAWS X-Rayを適用することができ、AWSのさまざまなサービスの連携をトレースできます。
特にAWS SNSなどはCloudWatchでトレースするとなると、呼び出しが失敗したのか、トリガーが失敗したのかなどをそれぞれログを確認することになるため大変です。
それをAWS X-Rayを使えばちょっとの実装だけでひと目で確認できるようになります。

また、Lambdaで所要時間が異様に時間が掛かっているがその原因がどこにあるのかをCloudWatchで見ようとすると、各ログの時間を調査していく必要がありますが、
詳細なトレース結果を見ることでX-Rayで簡単に突き止めることが出来るようにもなります。

CloudWatchでのトレースで苦労した経験ある方はぜひAWS X-Rayを適用してみてください。
それでは。

Acroquest Technologyでは、キャリア採用を行っています。

  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
モノリシックなアプリケーションをマイクロサービス化したいエンジニア募集! - Acroquest Technology株式会社のWeb エンジニア中途・インターンシップ・契約・委託の求人 - Wantedlywww.wantedly.com