Lambda で X-Ray アクティブトレース有効化と、追加で AWS X-Ray SDK を利用した際に可視化される内容の違いを見比べてみた

2021.12.25

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

一口に Lambda で X-Ray を有効化すると言ってもX-Ray アクティブトレースを有効化するだけもできますし、追加で AWS X-Ray SDK を利用してより詳細なトレーシングができます。

X-Ray で可視化したときにこの2パターンどのような違いがあるのでしょうか?また、X-Ray アクティブトレースを有効化するだけで得られるものは何か?違いを見比べてみましょう。

見比べた結果

Lambda コールドスタート時の様子を比較。クリックして拡大してみてね。

  • X-Ray SDK 追加すると Lambda から呼び出しているサービス、処理もトレースできる
X-Ray 有効 X-Ray SDK 追加
トレースマップ
  • X-Ray SDK 追加すると Lambda から呼び出しているサービス、処理にかかる時間を確認できる(緑枠の箇所が追加)
X-Ray 有効 X-Ray SDK 追加
詳細

検証環境

AWSが提供しているハンズオンの構成をベースにX-Rayを追加します。ハンズオン自体は以前に「やってみたブログ」があるので以下を参考ください。

初心者向けハンズオンで解説が非常に丁寧なため構成の解説はハンズオン動画にお任せします。追加した X-Ray について設定方法、可視化結果を解説します。

構成図

API Gateway の URL に POST すると API Gateway で受け付けて翻訳Lambdaを起動します。

画像引用: ハンズオンのアンケート回答後にダウンロードできる資料より

バージョン情報

ローカル端末で作成したSAMテンプレート、Lambda関数をsam deployでAWSへ展開します。

Product Version
OS macOS 11.6
SAM CLI 1.36.0
Python 3.9
aws-xray-sdk 2.9.0

X-Ray なしの構成

ハンズオンの内容をベースに多少変更箇所がありますが概ね同じ内容です。簡単に説明します。

  • Lambda に割り当ているポリシーがFullAccessですので動作検証以外で参考にする場合は必要に応じて制限してください。
  • /translateに対してリクエストメソッドがPOSTだと翻訳Lambdaが起動します。
    • リクエストボディを翻訳するのですがその処理は翻訳Lambda側になります。

template.yaml

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: Learn about X-Ray

Globals:
  Function:
    Timeout: 10

Resources:
  TestLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: sample-function
      CodeUri: ./sample
      Handler: sample.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      Timeout: 5
      MemorySize: 256
      Events:
        PostApi:
          Type: Api
          Properties:
            Path: /test
            Method: get
            RestApiId: !Ref TranslateAPI
  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translate-function
      CodeUri: ./translate-function
      Handler: translate-function.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      Timeout: 5
      MemorySize: 256
      Policies:
        - TranslateFullAccess
        - AmazonDynamoDBFullAccess
      Events:
        PostApi:
          Type: Api
          Properties:
            Path: /translate
            Method: post
            RestApiId: !Ref TranslateAPI

  TranslateAPI:
    Type: AWS::Serverless::Api
    Properties:
      Name: translate-api
      StageName: dev
      EndpointConfiguration: REGIONAL

  TranslateDynamoDbTbl:
    Type: AWS::DynamoDB::Table
    Properties:
      BillingMode: PAY_PER_REQUEST
      TableName: translate-history
      AttributeDefinitions:
        - AttributeName: timestamp
          AttributeType: S
      KeySchema:
        - AttributeName: timestamp
          KeyType: HASH
  • Amazon Translate と利用して日本語から英語に翻訳します。
  • 翻訳結果を DyanamoDB へ記録します。
  • JSON 形式で翻訳結果が返ってきます。

translate-function.py

import json
import boto3
import datetime

translate = boto3.client(service_name='translate')

dynamodb_translate_history_tbl = boto3.resource(
    'dynamodb').Table('translate-history')


def lambda_handler(event, context):

    input_text = event['body']

    response = translate.translate_text(
        Text=input_text,
        SourceLanguageCode="ja",
        TargetLanguageCode="en"
    )

    output_text = response.get('TranslatedText')

    dynamodb_translate_history_tbl.put_item(
        Item={
            "timestamp": datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
            "input": input_text,
            "output": output_text
        }
    )

    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
        }),
        'isBase64Encoded': False,
        'headers': {}
    }

実行結果は以下の通り。POSTしたリクエストボディを翻訳された結果のレスポンスを受け取ります。

$ curl -XPOST -d '網走出身です' https://api.example.com/v1/translate
{"output_text": "I'm from Abashiri"}⏎

X-Ray アクティブトレース有効化

SAMテンプレートでの X-Ray 有効化は手軽です。Lambda の他に API Gateway も利用しているので合わせて X-Ray を有効化します。

Globalsセクションに以下の様に追加するだけです。個別にAWS::Serverless::Functionや、AWS::Serverless::ApiPropertiesに追加しなくて済みます。

template.yaml

Globals:
  Function:
    Timeout: 10
    Tracing: Active # Lambda での X-Ray 有効化
  Api:
    TracingEnabled: True # API Gateway での X-Ray 有効化

X-Ray デーモンを使用するために書き込み可能なアクセス権限を付与します。

  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translate-function
      CodeUri: ./translate-function
      Handler: translate-function.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      Timeout: 5
      MemorySize: 256
      Policies:
        - TranslateFullAccess
        - AmazonDynamoDBFullAccess
        - AWSXRayDaemonWriteAccess

参考

SAMテンプレート全文

折りたたみ
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: Learn about X-Ray

Globals:
  Function:
    Timeout: 10
    Tracing: Active # LambdaでのX-Ray有効化
  Api:
    TracingEnabled: True # API GatewayでのX-Ray有効化

Resources:
  TestLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: sample-function
      CodeUri: ./sample
      Handler: sample.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      Timeout: 5
      MemorySize: 256
      Policies:
        - AWSXRayDaemonWriteAccess
      Events:
        PostApi:
          Type: Api
          Properties:
            Path: /test
            Method: get
            RestApiId: !Ref TranslateAPI
  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translate-function
      CodeUri: ./translate-function
      Handler: translate-function.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      Timeout: 5
      MemorySize: 256
      Policies:
        - TranslateFullAccess
        - AmazonDynamoDBFullAccess
        - AWSXRayDaemonWriteAccess
      Events:
        PostApi:
          Type: Api
          Properties:
            Path: /translate
            Method: post
            RestApiId: !Ref TranslateAPI

  TranslateAPI:
    Type: AWS::Serverless::Api
    Properties:
      Name: translate-api
      StageName: dev
      EndpointConfiguration: REGIONAL

  TranslateDynamoDbTbl:
    Type: AWS::DynamoDB::Table
    Properties:
      BillingMode: PAY_PER_REQUEST
      TableName: translate-history
      AttributeDefinitions:
        - AttributeName: timestamp
          AttributeType: S
      KeySchema:
        - AttributeName: timestamp
          KeyType: HASH

Lambda関数は変更することなくデプロイします。

デプロイ結果

Lambda の X-Ray アクティブトレースが有効化されています。

API Gateway の X-Ray トレースも有効化されています。

Lambda関数には全く手を入れないかたちで X-Ray を有効化しました。

X-Ray の結果

この設定だけでも可視化してくれます。

トレースマップは API Gateway と Lambda のみ表示されています。ですが、Lambda から Translate や、 DyanamoDB にアクセスしている様子はわかりません。

Lambda で X-Ray アクティブトレースを有効化すると以下の項目の取得、可視化ができます。

  • Initialization: Lambda実行環境ライフサイクルの初期化フェーズです。
    • コールドスタートにかかる時間ですね。
  • Invocation: Lambdaが関数ハンドラを呼び出すフェーズです。
    • ランタイムと拡張機能の登録から始まり、ランタイムがレスポンスを送信する準備ができた時点で終了します。
  • Overhead: ランタイムがレスポンスを送信してから、次の呼び出しシグナルが送られるまでの間のフェーズです。

参考

X-Ray SDK for Python 追加

X-Ray SDK を Lambda関数に組み込んで違いを確認します。X-Ray SDK が対応しているライブラリに対しては以下の2行だけでパッチをあてることができます。これだけで AWS SDK を利用している Translate と、DyanamoDB は X-Ray のセグメントを自動作成してくれます、便利。

セグメントについては以下のリンクをご参照ください。

対応ライブラリ一覧

translate.py

import json
import boto3
import datetime
from aws_xray_sdk.core import patch_all

patch_all()

translate = boto3.client(service_name='translate')

X-Ray SDK for Pythonライブラリが必要になりますのでrequirements.txtに書いておきます。

requirements.txt

aws-xray-sdk

X-Ray for Python 追加後のコード全文

折りたたみ
import json
import boto3
import datetime
from aws_xray_sdk.core import patch_all

patch_all()

translate = boto3.client(service_name='translate')

dynamodb_translate_history_tbl = boto3.resource(
    'dynamodb').Table('translate-history')


def lambda_handler(event, context):

    input_text = event['body']

    response = translate.translate_text(
        Text=input_text,
        SourceLanguageCode="ja",
        TargetLanguageCode="en"
    )

    output_text = response.get('TranslatedText')

    dynamodb_translate_history_tbl.put_item(
        Item={
            "timestamp": datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
            "input": input_text,
            "output": output_text
        }
    )

    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
        }),
        'isBase64Encoded': False,
        'headers': {}
    }

SAMテンプレートの変更ないです。デプロイします。

X-Ray の結果

トレースマップが少し増えています。

Lambda関数で利用していた他AWSサービスが可視化されました。

invocationが細分化され、translateDyanamoDB の処理時間を確認できます。

翻訳に時間かかるケース

翻訳する文字量を大幅に増やしてリクエスト投げて比較してみます。

translateの処理時間が275msから581msへ伸びていることを確認できます。どこの処理に時間がかかっているのか特定が容易ですね。

それとInitializationの項目がないことを確認できます。連続して実行したためウォームスタートからの起動だったため、初期化の処理が走らなかった(コールドスタートではない)ことを確認できます。

まとめるとtranslateの処理時間は長くなったもののInitializationがなかったため、トータル実行時間は翻訳に時間かかるケースの方が早かったことが読みとれます。

おわりに

どういった違いがあるのか比較しておきたかったので冒頭にキャプチャを比較してあります。 今回はPythonのLambdaでしたが、AWS X-Ray SDK に対応したライブラリなら Lambda関数への追加もpatch_all()だけで簡単ですね。

参考