AWS再入門ブログリレー2022 X-Ray編

こんにちは、AWS事業本部コンサルティング部の枡川です。
当エントリは弊社コンサルティング部による『AWS再入門ブログリレー2022』の37日目のエントリです。
このブログリレーの企画は、普段AWSサービスについて最新のネタ・深い/細かいテーマを主に書き連ねてきたメンバーの手によって、今一度初心に返って、基本的な部分を見つめ直してみよう、解説してみようというコンセプトが含まれています。
AWSをこれから学ぼう!という方にとっては文字通りの入門記事として、またすでにAWSを活用されている方にとってもAWSサービスの再発見や2022年のサービスアップデートのキャッチアップの場となればと考えておりますので、ぜひ最後までお付合い頂ければ幸いです。
では、さっそくいってみましょう。37日目のテーマは『AWS X-Ray』です。

AWS X-Rayとは

アプリケーションへのリクエストに関するデータを収集するAWSのマネージドサービスとなります。
CloudWatchを使用することでインフラレイヤでのパフォーマンスを確認できますが、X-Rayはアプリケーションレイヤを対象としてレスポンスタイムやレスポンスステータスなどの情報を収集します。
特にマイクロサービスのように多くのサービスが呼び出し合う際に、アプリケーションのパフォーマンス問題やそのボトルネックについて特定するのに役立ちます。
X-Rayはアプリケーションとは別プロセスで起動するエージェント(X-Rayデーモン)を使用します。
アプリケーションからトレース情報を収集した後にSDKを使用して、X-Rayデーモンに送信します。
X-RayデーモンがデータをバッファリングしてX-Ray APIにデータを定期的に転送するというのが基本的な動きとなります。
EC2だけでなく、ECSやLambda、API Gatewayなど非常に多くのサービスと統合して使用することができ、統合する方法はサービスによって異なります。
ECSではサイドカーを使用したり、Lambdaではマネジメントコンソールからアクティブトレースを有効化するだけで使えたりします。
SDKや各サービスとの統合により、AWS上のサービスのパフォーマンスを統一された方法で確認することができます。

AWS X-Rayの概念

X-Rayは各リクエストの情報をトレース、セグメント、サブセグメントという階層に整理して扱います。

(引用)AWS Blackbelt Online Seminar AWS X-Ray

セグメントは動作に関するデータであり、誰がどのサービスにどんなリクエストを行ったかという情報を含みます。
(引用)AWS Blackbelt Online Seminar AWS X-Ray

サブセグメントは呼び出しに関する追加の情報であり、例えば、Lambdaへのリクエストの中でDynamoDBへリクエストが実行された場合、それらはサブセグメントとして記録されます。
ALBへリクエストした際に他のサービスへのリクエストの結果を元にレスポンスを返した場合は、その他サービスへのリクエストがサブセグメントとなります。
(引用)AWS Blackbelt Online Seminar AWS X-Ray

リクエストの中に他サービスへのリクエストがある際にX-Rayがどのように記録するかは後ほど確認してみます。

サンプルアプリケーションを作ってサービスマップを見てみる

X-Rayはアプリケーションがあることが前提のサービスとなるために手軽に試しづらいです。
しかし、公式ドキュメントのサンプルに従って進めることで簡単にElastic Beanstalkのアプリケーションを使用して試すことができます。

ECSで試してみたい場合はaws-samplesリポジトリにある下記も使用できます。
GitHub - aws-samples/aws-xray-fargate: Code examples showing how to run AWS X-Ray as a sidecar container on Fargate for deep application insights.
東京リージョンで試してみた記事は下記エントリになるので、試す際は参考にして下さい。

下記公式チュートリアルもおすすめです。

こちらはX-Rayも含めたAWSの監視サービス全体を学ぶことができます。
このチュートリアルは、正にマイクロサービスって感じのサービスが立ち上がって壮観です。

試してみたブログもあります。

今回はaws-sampleのECS Fargateを使用するサンプルを触ってみます。
ECSでは下記画像のようなサイドカーでデーモンを実行します。
サイドカーコンテナの公式イメージも用意されているのでそれを使用しています。

このアプリはClientがServiceAにアクセスすると、ServiceAからServiceBへリクエストがとぶような構造になっています。
ServiceB側に50%の確立で403エラーを返す機構があるので、極端なストレステストをしなくともサービスマップに200レスポンス以外のトレースを混ぜることができます。

(引用)GitHub - aws-samples/aws-xray-fargate: Code examples showing how to run AWS X-Ray as a sidecar container on Fargate for deep application insights.

X-Rayがアプリケーションのパフォーマンスを自動で視覚化してくれるサービスである、サービスマップを見てみます。
X-Rayの中で花形にあたる機能だと思っています。

平均レスポンスタイムや、単位時間あたりのトレース数が記載されています。
今回はシンプルな構造ですが、サービス数が増えてくるとサービスマップで図示することのメリットが大きく、全体のパフォーマンスに影響するリクエストを見つけるのにとても役立ちます。
トラフィックの量に応じて円の大きさを変えるようなことも可能です。
また、リクエストは下記のように色分けして表示されます。

  • 緑:正常な呼び出し
  • 赤:5XXエラー(サーバ障害)
  • 黄:4XXエラー(クライアントエラー)
  • 紫:429リクエスト(スロットリングエラー)

今回は確率で403エラーを発生させているので、その割合だけ黄色く着色されています。

セグメント構造

実際にトレースから各セグメントのRawデータをjson形式で見ることが可能です。
jsonからもセグメントとサブセグメントに分けてデータを扱っていることが見てとれます。
セグメントはstart_timeend_timeといったフィールドの他、HTTPリクエストの詳細情報を記録するhttpといったフィールドなどを保持しています。

今回の場合、ServiceAに対して1セグメント、ServiceBに対して1セグメントがある形となります。
ServiceAへリクエストを実施した際、やり取りの中でServiceBへリクエストがなされるため、その分がServiceAのサブセグメントとして記録されています。
また、ServiceAへのリクエストにあたるセグメントにはparent_idは存在しませんが、ServiceBへのリクエストにはparents_idが存在します。
これらを使用して、どのセグメントから呼び出されたかの情報を保持しています。

{
    "Id": "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "Duration": 0.012,
    "LimitExceeded": false,
    "Segments": [
        {
            "Id": "74315e1e5eadaf1b",
            "Document": {
                "id": "74315e1e5eadaf1b",
                "name": "x-ray-test-alb-2000110801.ap-northeast-1.elb.amazonaws.com",
                "start_time": 1648210028.556,
                "trace_id": "1-623db06c-7aad45e40389b8f527905ef3",
                "end_time": 1648210028.559,
                "parent_id": "7786108cf08d1821",
                "http": {
                    "request": {
                        "url": "http://<ServiceBのURL>/create",
                        "method": "POST",
                        "user_agent": "",
                        "client_ip": "xx.xx.xx.xx",
                        "x_forwarded_for": true
                    },
                    "response": {
                        "status": 200
                    }
                },
                "aws": {
                    "ecs": {
                        "container": "ip-10-0-0-188.ap-northeast-1.compute.internal"
                    },
                    "xray": {
                        "package": "aws-xray-sdk",
                        "sdk_version": "3.3.4",
                        "sdk": "X-Ray for Node.js"
                    }
                },
                "service": {
                    "name": "unknown",
                    "version": "unknown",
                    "runtime": "node",
                    "runtime_version": "v8.17.0"
                },
                "origin": "AWS::ECS::Container"
            }
        },
        {
            "Id": "c79b3ab5e9522982",
            "Document": {
                "id": "c79b3ab5e9522982",
                "name": "service-a-alb-100671050.ap-northeast-1.elb.amazonaws.com",
                "start_time": 1648210028.55,
                "trace_id": "1-623db06c-7aad45e40389b8f527905ef3",
                "end_time": 1648210028.562,
                "http": {
                    "request": {
                        "url": "http://<ServiceAのURL>",
                        "method": "GET",
                        "user_agent": "curl/7.81.0",
                        "client_ip": "xx.xx.xx.xx",
                        "x_forwarded_for": true
                    },
                    "response": {
                        "status": 200
                    }
                },
                "aws": {
                    "ecs": {
                        "container": "ip-10-0-0-63.ap-northeast-1.compute.internal"
                    },
                    "xray": {
                        "package": "aws-xray-sdk",
                        "sdk_version": "3.3.4",
                        "sdk": "X-Ray for Node.js"
                    }
                },
                "annotations": {
                    "service": "service-b-request"
                },
                "service": {
                    "name": "unknown",
                    "version": "unknown",
                    "runtime": "node",
                    "runtime_version": "v8.17.0"
                },
                "origin": "AWS::ECS::Container",
                "subsegments": [
                    {
                        "id": "7786108cf08d1821",
                        "name": "x-ray-test-alb-2000110801.ap-northeast-1.elb.amazonaws.com",
                        "start_time": 1648210028.55,
                        "end_time": 1648210028.561,
                        "http": {
                            "request": {
                                "url": "http://<ServiceBのURL>/create",
                                "method": "POST"
                            },
                            "response": {
                                "status": 200,
                                "content_length": 50
                            }
                        },
                        "namespace": "remote"
                    }
                ]
            }
        }
    ]
}

X-Ray Analytics

X-Ray Analyticsはトレースデータに対して視覚化や分析を行い、パフォーマンスについて洞察を得るのに使用するサービスです。
(引用)AWS Blackbelt Online Seminar AWS X-Ray

Analyticsの主要な機能として、応答時間の分布を表示することが可能です。
全リクエストの内、時間がかかっているものがどれくらいあるか一目瞭然です。
ドラッグすることで、レスポンスに時間がかかっているリクエストの情報を簡単に集計できます。(対象は青く着色されます)
時間がかかっているリクエストがいつ頃発生したのか、それらのHTTP Statusコードは何なのかなどの情報を取得できます。

また、時系列アクティビティを表示する機能も存在します。
時間帯ごとに、どの程度トレースが発生しているかを色の濃さでわかりやすく表示してくれます。
時系列アクティビティでも時間帯ごとのトレースを簡単に集計することが可能です。

X-Ray Insights

Analyticsがトレースデータを上手く視覚化して洞察を得るためのサービスであるのに対して、X-Ray Insightsはパフォーマンスの異常とその影響を自動で検知してくれるようなサービスになります。
X-Rayが自動でトレースから異常を検知した後は、Event Bridgeを使用して通知を行うようなことも可能です。
このサービスは現時点でデフォルトで有効化されておらず、自分で有効化する必要があります。
正直な所全然触れることができておらず、再入門ブログリレーが始まった頃はX-Ray Insightsをガッツリ触って詳細に書こうというモチベーションがあったのですが、間に合わなかったのでいずれブログを書きたいと思っています...

サンプリング

記録するリクエストをどの程度記録するかを指定します。(デフォルトでは全てのリクエストを収集しているわけではありません)
マネジメントコンソールから見るとデフォルトでは下記のような設定になっていました。
1秒につき1トレースはレートに関わらずに記録し、それを超える分は5%を取得する設定になります。

料金影響と確認したい対象を考慮しつつ、新しいサンプリングルールを作成して使用することも可能です。
新しく作成する時は優先度は低い方が優先されることに気をつけて下さい。

最後に

以上、『AWS再入門ブログリレー2022』の37日目のエントリ『AWS X-Ray』編でした。
3/28(月)はたかくにさんの「Amazon DynamoDB」の予定です。お楽しみに!!