はじめに
分散トレーシングについて勉強したので、AWSのサービスであるAWS X-rayで遊んでみようと思います。Amazon SNSのX-Rayアクティブトレースのサポートの開始が2023年2月と割と最近だったので1、API Gateway → Lambda → SNS → SQS → Lambdaまでのトレースを繋げてみました。
AWS X-rayとは
AWSが提供する分散トレーシングのためのサービスです。アプリケーションのパフォーマンスを測定するなどに利用できます。詳しくは、公式のドキュメントを参照してください。
実験の構成
API GatewayからLambda(testLambda1)を呼び出し、SNSとSQSを経由して別のLambda(testLambda2, testLambda3)が起動するまでのリクエストを繋げてみます。ざっくりとした構成図は図のとおりです。基本的にはデフォルトの設定で作成していますが、一部設定を変更している箇所があるので、そこだけピックアップします。
API Gateway
API Gatewayの「Enable X-ray Tracing」にチェックをいれます。
Lambda
設定から、アクティブトレースを有効にします。
実験に利用したAWS Lambdaのコード
AWS Lambdaのデフォルトで利用できるbotocoreのバージョンが低いので、botocoreのバージョンを最新にします。botocoreのバージョンを上げる理由は後述します。
今回の実験で使うAWS Lambdaは基本的にsnsへのpublishとsqsのメッセージを受け取るだけの処理をおこなっているだけです。
import json
import botocore
import boto3
import os
def lambda_handler(event, context):
s3 = boto3.client('s3')
sns = boto3.client('sns')
topic_arn = 'SNS_TOPIC_ARN' # sns_topicのARNを設定
message = 'hoge'
response = sns.publish(
TopicArn=topic_arn,
Message=message
)
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
import json
def lambda_handler(event, context):
# TODO implement
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
import json
import boto3
def lambda_handler(event, context):
sqs = boto3.client('sqs')
queue_url = 'QUEUE_URL' # queueのURLを設定
response = sqs.receive_message(
QueueUrl=queue_url,
MaxNumberOfMessages=1
)
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
SNS
SNSの設定から、「アクティブトレースを使用する」を選択します。
結果
一連のリクエストのトレースは、CloudWatch X−rayトレーシングのServiceMapから確認できます。
API Gatewayから始まり、SNSを経由して分かれるtestLambda2, testLambda3までのリクエストのトレースを確認することができました。
各セグメントの詳細も確認することができます。
つまづいた点
現在(2023年4月3日)のAWS Lambdaのランタイムにおけるbotocoreのバージョンが1.23.32です2。
その場合だと、Lambda → SNS → Lambdaのリクエストが繋がらず、以下の図のとおりになりました。
botocoreのCHANGELOGを見てみるとSNSのActive Traceがサポートされたのがそのバージョン以降であり(以下にCHANGELOGからの引用)、実際にバージョンを上げることでリクエストが繋がることを確認できました。
1.29.69
...
- api-change:
sns
: This release adds support for SNS X-Ray active tracing as well as other updates.
追記(2023/05/22)
AWS Lambdaのランタイムのバージョンが上がったのでこの手順は必要ないかもしれません。
SDKなどを使ってもう少し詳しくトレースを取ってみる
SDKなどを用いることで、アプリケーションをより詳しく計測することができます。大きく2つの方法があると思います。
- AWS X-ray SDK
- AWSDistro for OpenTelemetry
詳しくはドキュメントを参考にしてください。
今回は、AWS X-ray SDKを使って簡単にS3へアクセスしている場合について確認してみようと思います。
import json
import boto3
from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.core import patch_all
patch_all()
def lambda_handler(event, context):
xray_recorder.begin_segment("sdk test")
sqs = boto3.client('sqs')
queue_url = 'QUEUE_URL' # queueのURLを設定
response = sqs.receive_message(
QueueUrl=queue_url,
MaxNumberOfMessages=1
)
s3 = boto3.client('s3')
# 保存するデータ
data = "Hello, World!"
# S3バケット名と保存先のオブジェクトキーを指定
bucket_name = 'my-bucket' # bucket名
object_key = 'example.txt'
# S3にデータを保存
s3.put_object(Bucket=bucket_name, Key=object_key, Body=data)
xray_recorder.end_segment()
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
testLambda3の方にS3へのアクセスが伸びていることが確認できました。
AWS SNSのActive Traceをオフにしてみる
AWS SNSのActive TraceをオフにするとSNSのノードが消えました。すでにトレースが設定されているリクエストの場合は、Active Traceが設定されていなくともパススルーしてくれるそうです。
おわりに
今回の実験ではAWSの操作をChatGPTを使って色々聞いてみました。権限を追加する際に答えとして帰ってきたポリシーをそのまま使えたり、AWSの操作が曖昧なところの最初のアクションを起こしやすかったのでやりやすかったです。しかし、下の図のようにたまにそれっぽい嘘を言うので面白いですね。