この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
西田@大阪です。今回は Lambda から X-Ray に対してのカスタムセグメントを送信して、その情報を検索してみたいと思います
このエントリはServerless Advent Calendar 2017 16日目の記事です
X-Rayで使われる用語
単語 | 意味 |
---|---|
セグメント | X-Rayの基本となるトレースデータ |
サービス | マイクロサービスにおける1つのサービスを表す。Lambdaであったり、HTTPサーバーなど |
ダウンストリーム | サービスから呼び出される別のサービス、もしくはDynamoDB、PostgreSQL、MySQLなどのミドルウェア |
セグメント
X-Rayの基本となるデータです。最低限必要なパラメーターとしては以下になります
項目 | 説明 |
---|---|
name | セグメントの名前 |
id | セグメントのID |
trace_id | 複数のサービスのトラッキングに使われるID |
start_time | 計測開始時間 |
end_time | 計測終了時間 |
サブセグメント
サブセグメントは一つのサービスの中でダウンストリームの呼び出し、計測したい任意の処理をトレースするためのものです
最低限必要なパラメーターに以下のパラメーターが追加されます。
項目 | 説明 |
---|---|
parent_id | 親のセグメントのID |
parent_id
に親のセグメントのIDを設定することによって、親子関係をトレースできるようになります
Node.jsの X-Ray SDKだとキャプチャ関数内で現在のコンテキストから取得できるセグメントのIDが parent_id
にセットされたサブセグメントが生成されます
AWSXRay.captureAsyncFunc('send', function(subsegment) {
// この subsegment の prent_id には今のコンテキストのセグメントのIDが設定されている
sendRequest(host, function() {
console.log('rendering!');
res.render('index');
subsegment.close();
});
});
Lambdaのカスタムサブセグメントを送信する
Lambdaを作成しアクティブトレースを有効にする
Lambdaのblue printから microservice-http-endpoint と DynamoDB を作成します
以下の記事が参考になります
Lambda作成後Lambdaの設定画面からアクティブトレースを有効にするをチェックし保存します
カスタムサブセグメントを送信する
X-Ray SDKを宣言します
const AWSXRay = require('aws-xray-sdk-core');
X-Ray SDK の captureAsyncFunc
を使用し非同期の関数を計測するサブセグメントを作成します
以下の例では非同期処理の計測を行い検索用のAnnotation
をサブセグメントに追加しています
AWSXRay.captureAsyncFunc('timeout', (subsegment) => {
// この subsegment の parent_id には今のコンテキストのセグメントのidが設定されている
setTimeout(()=>{
console.log('Do Async');
subsegment.addAnnotation("key", "setTimeout");
subsegment.close();
}, 2000);
});
X-Rayのサービスマップで確認する
annotationはannotation.<キー> = "<値>"
のシンタックスで検索できます
検索結果より、トレースされた内容を確認します
内容を確認すると setTimeout
で設定した2秒かかってることがわかります
Lambdaから別のLambdaの呼び出しをトレースする
AWS SDK を X-Ray SDK をつかってトレースできるようにします
const AWS = AWSXRay.captureAWS(require('aws-sdk'));
const Lambda = new AWS.Lambda({});
後は呼び出しを行うだけで、Lambdaの呼び出しリクエストに X-Amzn-Trace-Id
ヘッダが付与され、呼び出された側のLambdaのセグメントのtrace_idとして利用されます
Lambda.invoke({
FunctionName: "x-ray-sample-2",
Payload: JSON.stringify(event, null, 2)
}, (error, data) => {
if (error) {
console.log(error);
console.log('failed to invoke another lambda');
} else {
console.log('Succeed to call another lambda');
}
});
これはX-Ray SDK の captureAWS
関数内で AWS SDK の HTTPリクエストをカスタマイズする仕組みを使って X-Amzn-Trace-Id
ヘッダをつなぐフックが設定されるからです
var captureAWS = function captureAWS(awssdk) {
if (!semver.gte(awssdk.VERSION, minVersion))
throw new Error ('AWS SDK version ' + minVersion + ' or greater required.');
for (var prop in awssdk) {
if (awssdk[prop].serviceIdentifier) {
var Service = awssdk[prop];
// フックする処理を登録
Service.prototype.customizeRequests(captureAWSRequest);
}
}
return awssdk;
};
function captureAWSRequest(req) {
// ~~~ 省略
req.on('build', function(req) {
// X-Amzn-Trace-IdをHTTPヘッダに設定
req.httpRequest.headers['X-Amzn-Trace-Id'] = 'Root=' + traceId + ';Parent=' + subsegment.id +
';Sampled=' + (subsegment.segment.notTraced ? '0' : '1');
}).on('complete', function(res) {
subsegment.addAttribute('namespace', 'aws');
subsegment.addAttribute('aws', new Aws(res, subsegment.name));
// ~~~ 省略
サービスマップでLambda同士がつながっていることが確認できます
呼び出された側のトレースもできてることが確認できます
最後に
いかかでしたでしょうか?
X-Rayの仕組みを理解しカスタムセグメントを活用すれば、任意の処理を計測することが容易になります
複雑で大規模のシステムになればなるほど、活用できる場面が多くなるのではないでしょうか
次回はX-Ray SDK の仕組みについて深く調べて見たいと思います