AWS Lambda サーバーレスアプリケーションによる分散型トレーシング
Datadog では、サーバーレストレースをメトリクスに接続することで、アプリケーションのパフォーマンスに関する豊富な情報を提供します。これにより、サーバーレスアプリケーションの性質である分散型の環境でもパフォーマンスの問題を的確にトラブルシューティングできます。
Datadog Python、Node.js、Ruby、Go、Java、.NET SDK は、AWS Lambda の分散型トレーシングをサポートしています。
サーバーレスアプリケーションからトレースを送信する
Datadog Python、Node.js、Ruby、Go、Java、.NET SDK は、AWS Lambda の分散型トレーシングをサポートしています。SDK はインストール手順に従ってインストールできます。
ランタイムの推奨事項
Python と Node.js
Python および Node.js 用の Datadog Lambda ライブラリと SDK は、次の機能をサポートしています。
- Lambda ログおよびトレースとトレース ID およびタグ挿入との自動相関。
- Serverless Framework、AWS SAM、AWS CDK インテグレーションを使用したコード変更なしのインストール。
- ダウンストリームの Lambda 関数またはコンテナを呼び出す HTTP リクエストのトレース。
- AWS SDK で実行された Lambda の連続呼び出しのトレース。
- コールドスタートのトレース
- AWS Managed Services を介した非同期 Lambda 呼び出しのトレース
- API Gateway
- SQS
- SNS
- SNS と SQS の直接インテグレーション
- Kinesis
- EventBridge
- DynamoDB
- S3
- Step Functions
- すぐに使用できる数十の追加の Python および Node.js ライブラリのトレース。
Datadog では、Python および Node.js のサーバーレスアプリケーション用に Datadog SDK をインストールすることを推奨します。
上記にリストされていないサーバーレスリソースのトレースをご希望の場合は、機能リクエストを開いてください。
Ruby
Ruby 用の Datadog Lambda ライブラリと SDK は、次の機能をサポートしています。
- Lambda ログおよびトレースとトレース ID およびタグ挿入との自動相関。
- ダウンストリームの Lambda 関数またはコンテナを呼び出す HTTP リクエストのトレース。
- すぐに使用できる数十の追加の Ruby ライブラリのトレース。
Datadog では Datadog SDK を使用してサーバーレス関数をトレースできます。
上記にリストされていないサーバーレスリソースのトレースをご希望の場合は、機能リクエストを開いてください。
Go
Go 用の Datadog Lambda ライブラリと SDK は、次の機能をサポートしています。
- Lambda ログおよびトレースとトレース ID およびタグ挿入との手動相関。
- ダウンストリームの Lambda 関数またはコンテナを呼び出す HTTP リクエストのトレース。
- すぐに使用できる数十の追加の Go ライブラリのトレース。
Datadog では、Go のサーバーレスアプリケーション用に Datadog SDK をインストールすることを推奨します。
上記にリストされていないサーバーレスリソースのトレースをご希望の場合は、機能リクエストを開いてください。
Java
Java 用の Datadog Lambda ライブラリと SDK は、次の機能をサポートしています。
- Lambda ログおよびトレースとトレース ID およびタグ挿入との相関。詳細については、Java ログとトレースの接続を参照してください。
- ダウンストリームの Lambda 関数またはコンテナを呼び出す HTTP リクエストのトレース。
- すぐに使用できる数十の追加の Java ライブラリのトレース。
Datadog では、Java のサーバーレスアプリケーション用に Datadog SDK をインストールすることを推奨します。
Java Lambda 関数用の Datadog SDK に関してフィードバックがございましたら、Datadog Slack コミュニティの #serverless チャネルで行われているディスカッションをご確認ください。
.NET
.NET 用の SDK は、次の機能をサポートしています。
- ダウンストリームの Lambda 関数またはコンテナを呼び出す HTTP リクエストのトレース。
- すぐに使用できる数十の追加の .NET ライブラリのトレース。
Datadog では、.NET のサーバーレスアプリケーション用に Datadog SDK をインストールすることを推奨します。
.NET Azure サーバーレスアプリケーションを介したトレースの詳細をご覧ください。
スパンの自動リンク
Datadog は、非同期リクエストのセグメントがトレースコンテキストを伝播できない場合に、リンクされたスパンを自動的に検出します。たとえば、リクエストによって S3 変更イベント や DynamoDB ストリーム がトリガーされる場合などです。自動リンクされたスパンは Span Links タブに表示されます。Backward または Forward のいずれかとして示されます。
Backward: 表示されているトレースによって発生したリンクスパン。
Forward: 表示されているトレースを発生させたリンクスパン。
サンプリングや
トレース保持フィルターが自動リンクに干渉することがあります。自動リンクされたスパンが表示される可能性を高めるには、サンプルレートを上げるか、保持フィルターを調整してください。
対応テクノロジー
スパンの自動リンクは、次の対象に利用可能です。
DynamoDB 変更ストリームの自動リンク
DynamoDB Change Stream について、スパンの自動リンクは次の操作をサポートしています。
PutItemUpdateItemDeleteItemBatchWriteItemTransactWriteItems
S3 Change Notification の自動リンク
S3 Change Notificationについて、スパンの自動リンクは次の操作をサポートしています。
PutObjectCompleteMultipartUploadCopyObject
ハイブリッド環境
Lambda 関数、ホスト、コンテナ、およびマネージドサービス全体でエンドツーエンドの可視性を得るには、Datadog SDK (dd-trace) を Lambda 関数とホストの両方にインストールします。これにより、インフラストラクチャーの境界を越えてリクエストの全体像がトレースに表示されます。
Lambda で、Datadog Lambda Extension を使用して dd-trace をインストールします。これにより、Lambda 実行環境内で Datadog Agent が実行され、最小限のオーバーヘッドでトレースが Datadog に直接送信されます。Lambda Extension は、新規と既存のどちらのサーバーレスアプリケーションにも推奨されるインストール方法です。
コンテナおよびホストベースの環境でのトレースのセットアップについては、Datadog APM のドキュメントを参照してください。
Lambda 関数のプロファイリング
Datadog の Continuous Profiler は、Python 向けにプレビュー版として提供されています。バージョン 4.62.0 およびレイヤーバージョン 62 以上で利用可能です。このオプション機能は、DD_PROFILING_ENABLED 環境変数を true に設定することで有効になります。
Continuous Profiler は、定期的にスレッドを起こして、実行中のすべての Python コードの CPU と ヒープのスナップショットを取得することで機能します。これにはプロファイラー自身も含まれる場合があります。プロファイラーが自分自身を無視するようにしたい場合は、DD_PROFILING_IGNORE_PROFILER を true に設定します。
トレースマージ
ユースケース
Datadog は Datadog APM トレースライブラリ (dd-trace) のみの使用を推奨していますが、高度な状況ではトレースマージを使って Datadog トレースと AWS X-Ray を組み合わせて使用することもできます。トレースマージは、Node.js と Python の AWS Lambda 関数で利用可能です。どの SDK を使用するかわからない場合は、SDK の選択をお読みください。
dd-trace と AWS X-Ray トレーシングライブラリの両方をインスツルメントするのは、主に 2 つの理由からです。
- AWS サーバーレス環境では、
dd-trace ですでに Lambda 関数をトレースしているため、Datadog APM がまだインスツルメントしていない AWS マネージドサービス (AppSync など) の AWS X-Ray アクティブトレースを要求して、dd-trace および AWS X-Ray スパンを単一トレースで視覚化します。 - Lambda 関数とホストの両方を使用するハイブリッド環境では、
dd-trace がホストをインスツルメントし、AWS X-Ray が Lambda 関数をインスツルメントするため、Lambda 関数およびホスト全体のトランザクションの接続済みトレースを視覚化します。
注: この場合、使用料が高額になる可能性があります。X-Ray スパンは、トレースのマージ後 2~5 分間は引き続き使用可能です。Datadog では、通常は、単一の SDK の使用をおすすめしています。SDK の選択方法についてご覧ください。
上記のユースケースをセットアップする手順は以下のとおりです。
AWS サーバーレス環境におけるトレースのマージ
AWS X-Ray は、バックエンド AWS サービス (AWS X-Ray アクティブトレース) とクライアントライブラリ一式の両方を提供します。Lambda コンソールでバックエンド AWS サービスのみを有効にすると、AWS Lambda 関数に Initialization と Invocation スパンが与えられます。API Gateway および Step Functions コンソールからも AWS X-Ray アクティブトレースを有効にできます。
AWS X-Ray SDK および Datadog APM クライアントライブラリ (dd-trace) は、いずれも関数に直接アクセスしてダウンストリームのコールのメタデータとスパンを追加します。dd-trace を使用してハンドラーレベルでトレースする場合は、次のようなセットアップになります。
- AWS Lambda コンソールおよび Datadog 内の AWS X-Ray インテグレーションで、Lambda 関数の AWS X-Ray アクティブトレースを有効にしてあります。
- 使用している Lambda ランタイム用のインストール手順に従い、Datadog APM (
dd-trace) を使用して Lambda 関数をインスツルメントしてあります。 dd-trace により、サードパーティライブラリにパッチが自動的に適用されているため、AWS X-Ray クライアントライブラリをインストールする必要はありません。- Lambda 関数で
DD_MERGE_XRAY_TRACES 環境変数を true に設定し、X-Ray と dd-trace トレースをマージします (Ruby では DD_MERGE_DATADOG_XRAY_TRACES)。
AWS Lambda とホスト全体のトレース
Datadog SDK によるコンテキストの伝播 (推奨)
Datadog SDK (dd-trace) を Lambda 関数とホストの両方にインストールします。これにより、AWS Lambda、コンテナ、オンプレミスホスト、マネージドサービスなど、インフラストラクチャーの境界を越えてリクエストの全体像がトレースに自動的に表示されます。
トレース伝搬
必須セットアップ
Lambda 関数を非同期でトリガーする Node や Python のサーバーレスアプリケーションで、1 つのつながったトレースを見るには、追加のインスツルメンテーションが必要になることがあります。Datadog でサーバーレスアプリケーションの監視を始めたばかりであれば、こちらの主なインストール手順に従い、SDK の選択に関するこのページをお読みください。Datadog Lambda Libraryを使って Lambda 関数から Datadog にトレースを送るようになったら、以下のようなケースではこれらの手順で 2 つの Lambda 関数間のトレースをつなぐとよいかもしれません。
- Step Functions で Lambda 関数をトリガーする
- MQTT など HTTP 以外のプロトコルで Lambda 関数を呼び出す
多くの AWS Managed サービス (こちらを参照) のトレースは、最初からサポートされており、このページで説明されている手順を実行する必要はありません。
トレースを送信するリソース間でトレースコンテキストを正常に接続するために、次のことが必要です。
- Datadog のトレースコンテキストを発信イベントに含める。発信イベントは、
dd-trace をインストールしたホストや Lambda 関数から発生させることができます。 - コンシューマー Lambda 関数内のトレースコンテキストを抽出する。
トレースコンテキストの受け渡し
以下のサンプルコードでは、HTTP ヘッダーをサポートしないサービスや、Datadog が Node や Python でネイティブに対応していないマネージドサービスに対して、発信ペイロードでトレースコンテキストを渡す方法について説明しています。
Python では、get_dd_trace_context ヘルパー関数を使用して、Lambda 関数内の発信イベントにトレースコンテキストを渡すことができます。
import json
import boto3
import os
from datadog_lambda.tracing import get_dd_trace_context # Datadog tracing helper function
def handler(event, context):
my_custom_client.sendRequest(
{
'myCustom': 'data',
'_datadog': {
'DataType': 'String',
'StringValue': json.dumps(get_dd_trace_context()) # Includes trace context in outgoing payload.
},
},
)
Node では、getTraceHeaders ヘルパー関数を使用して、Lambda 関数内の発信イベントにトレースコンテキストを渡すことができます。
const { getTraceHeaders } = require("datadog-lambda-js"); // Datadog tracing helper function
module.exports.handler = async event => {
const _datadog = getTraceHeaders(); // Captures current Datadog trace context.
var payload = JSON.stringify({ data: 'sns', _datadog });
await myCustomClient.sendRequest(payload)
ホストから
Lambda 関数からトレースコンテキストを渡していない場合、getTraceHeaders と get_dd_trace_context ヘルパー関数の代わりに次のコードテンプレートを使用すると、現在のスパンコンテキストを取得することができます。すべてのランタイムでこれを行う方法については、ここで説明しています。
const tracer = require("dd-trace");
exports.handler = async event => {
const span = tracer.scope().active();
const _datadog = {}
tracer.inject(span, 'text_map', _datadog)
// ...
上記のトレースコンテキストをコンシューマー Lambda 関数から抽出するには、Lambda 関数ハンドラーの実行前にトレースコンテキストをキャプチャするエクストラクター関数を定義する必要があります。これを行うには、エクストラクター関数の場所を指すように DD_TRACE_EXTRACTOR 環境変数を構成してください。フォーマットは <FILE NAME>.<FUNCTION NAME> です。たとえば、json エクストラクターが extractors.js ファイルにある場合は、extractors.json となります。Datadog は、エクストラクターを複数の Lambda 関数で再利用できるように、エクストラクターメソッドを 1 つのファイルにまとめて配置することを推奨しています。これらのエクストラクターは、どんなユースケースにも合うように完全にカスタマイズ可能です。
注:
- TypeScript や webpack のようなバンドラーを使用している場合、エクストラクターが定義されている Node.js モジュールを
import または require する必要があります。これにより、モジュールがコンパイルされ、Lambda のデプロイメントパッケージにバンドルされるようになります。 - Node.js の Lambda 関数が
arm64 上で動作する場合、環境変数 DD_TRACE_EXTRACTOR を使用する代わりに、関数コード内でエクストラクターを定義する必要があります。
以下のコードサンプルでは、サードパーティシステムや標準的な HTTP ヘッダーをサポートしない API にトレースコンテキストを伝達するために使用するエクストラクターのサンプルについて説明します。
def extractor(payload):
trace_headers = json.loads(payload["_datadog"]);
trace_id = trace_headers["x-datadog-trace-id"];
parent_id = trace_headers["x-datadog-parent-id"];
sampling_priority = trace_headers["x-datadog-sampling-priority"];
return trace_id, parent_id, sampling_priority
exports.json = (payload) => {
const traceData = payload._datadog
const traceID = traceData["x-datadog-trace-id"];
const parentID = traceData["x-datadog-parent-id"];
const sampledHeader = traceData["x-datadog-sampling-priority"];
const sampleMode = parseInt(sampledHeader, 10);
return {
parentID,
sampleMode,
source: 'event',
traceID,
};
};
var exampleSQSExtractor = func(ctx context.Context, ev json.RawMessage) map[string]string {
eh := events.SQSEvent{}
headers := map[string]string{}
if err := json.Unmarshal(ev, &eh); err != nil {
return headers
}
// Using SQS as a trigger with a batchSize=1 so it's important we check
// for this as a single SQS message will drive the execution of the handler.
if len(eh.Records) != 1 {
return headers
}
record := eh.Records[0]
lowercaseHeaders := map[string]string{}
for k, v := range record.MessageAttributes {
if v.StringValue != nil {
lowercaseHeaders[strings.ToLower(k)] = *v.StringValue
}
}
return lowercaseHeaders
}
cfg := &ddlambda.Config{
TraceContextExtractor: exampleSQSExtractor,
}
ddlambda.WrapFunction(handler, cfg)
X-Ray インテグレーションで Datadog にトレースを送信する
すでに X-Ray インスツルメンテーションがあり、引き続き利用する場合は、AWS X-Ray インテグレーションをインストールして、X-Ray から Datadog にトレースを送信できます。新しいサーバーレスアプリケーションの場合は、代わりに Datadog Lambda Extension を使用して Lambda 関数をインスツルメントすることをおすすめします。
参考資料