こんにちは!エンジニア3年目、フロントエンド&AWSサーバーレス系エンジニアを目指し勉強中のmiuraです。
サーバーレス構成だと簡単に立ち上げられる一方で、ある程度の開発規模になってくると非同期に連携したり、複数のサービスが関係したりするので、
エラーになった際にどこで失敗しているのか、デバッグしていくのが大変になることがありませんか?
または、レンスポンスが遅いと感じるがどのAWSサービスが起因して遅くなっているか確認するのが大変だと思ったことがありませんか?
そこで活躍するのがAWS X-Rayです。
AWS X-Rayはトレース対象であるサービスのリクエスト・レスポンス情報を収集するサービスで、
AWSコンソールにて収集した結果をマップ形式で見ることができ、各サービスの実行時間をグラフで可視化することができます。
今回はサーバーレスアプリへのX-Rayの適用を、Serverless Frameworkを用いて簡単に追加し、AWS上で可視化するところまでを紹介します。
全体構成
全体構成図中の①、②に分けて話をします。
①API GatewayからAWS Lambdaの実行
AWS LambdaがAPI Gatewayをトリガーとして実行されていることを可視化してみます。
②AWS LambdaからAWS SNSやDynamoDBの呼び出し
①で作成したAWS LambdaからAWS SNSを呼び出し、AWS SNSをトリガーに実行されるAWS LambdaにてDynamoDBの操作が行われていることを可視化してみます。
①API GatewayからAWS Lambdaの実行
以前使用したServerless Frameworkを今回も使います。
まずはPython3系用のサンプルプロジェクトを作成します。
serverless create --template aws-python3 --path aws-x-ray-serverless cd aws-x-ray-serverless
次に、Serverless FrameworkのX-Ray用プラグインをインストールし、serverless.ymlにAWS X-Rayを有効にする設定と
API Gatewayの設定を行います。
npm install aws-sdk aws-xray-sdk serverless-plugin-tracing
aws-x-ray-serverless/serverless.yml
service: aws-x-ray-serverless plugins: - serverless-plugin-tracing # トレース有効用のプラグイン provider: name: aws runtime: python3.6 region: us-west-2 apiKeys: - aws-x-ray-serverless-api-key tracing: true # X-Rayでのトレースを有効にする iamRoleStatements: - Effect: Allow Action: - xray:PutTraceSegments # X-Rayにセグメントドキュメントをアップロードする権限を付与する - xray:PutTelemetryRecords # X-Rayにテレメトリをアップロードする権限を付与する Resource: "*" functions: hello: handler: handler.hello events: - http: # API Gatewayの設定 path: hello method: get private: true
以上で、AWS X-RayおよびAPI Gatewayの設定ができました!
このようにプラグインをインストールし、serverless.ymlにたった数行設定を書くだけでX-Rayを適用することが出来ます。
早速、AWSにデプロイをしましょう。
sls deploy
デプロイが完了したら、curlコマンドやRestClientなどでAPI Gatewayを呼び出してLambdaを実行させます。
curl -s 【API GatewayのURl】 -H "x-api-key:【APIキー】"
すると、実行結果をAWSコンソールのX-Rayのサービスにて見ることが出来ます。
緑色の円が表示されていることからLambdaの実行は成功したことが分かります。
5xxエラーや4xxエラーなどがある場合、赤色や黄色で表示してくれるのでひと目でどこに問題があるかを確認できます。
中央の数字はそのサービスでの平均レスポンス時間と 1 分間に送信したトレース数を表しており、どこで処理に時間が掛かっているのかなども確認することが出来ます。
本格的なプロダクトともなると、多くのLambdaを互いに呼び出す形で作ることになります。
その際にどこでエラーになっているかを上図のようなサービスマップで簡単に確認できるのは、私のような開発者にとっては嬉しい機能ですよね。
また、円グラフをクリックすればさらに詳細なトレース情報を見ることが可能です。
トレースについては次の構成での結果で説明します。
②AWS LambdaからAWS SNSやDynamoDBの呼び出し
①でClient、API Gatewayを通してLambdaを実行する流れをAWS X-Rayで表示しました。
そこで次に、①の続きとしてAWS LambdaからAWS SNSやDynamoDBを呼び出して、それをAWS X-Rayで表示してみましょう。
まずは、AWS LambdaでのAWS SNSやDynamo DBの呼び出しをトレースをするためにPython用 AWS X-Ray SDKをインストールします。
pip install aws-xray-sdk -t .
次に自動生成したhandler.pyとserverless.ymlの一部を編集します。
aws-x-ray-serverless/handler.py
# -*- coding: utf-8 -*- import json import boto3 # AWS X-Rayのライブラリを読み込み from aws_xray_sdk.core import xray_recorder from aws_xray_sdk.core import patch_all # AWS X-Rayのパッチを適用 patch_all() def hello(event, context): body = { "message": "Go Serverless v1.0! Your function executed successfully!", "input": event } # AWS SNSを呼び出し sns = boto3.client('sns') try: sns.publish( TopicArn="arn:aws:sns:us-west-2:471043657237:hello", Subject=body['message'], Message=json.dumps(body['input']) ) except Exception: raise response = { "statusCode": 200, "body": json.dumps(body) } return response # AWS SNSで受け取った情報をDynamoDBに保存するLambdaスクリプト def put_hello(event, context): sns = event['Records'][0]['Sns'] dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('hello_log') try: table.put_item( Item={ "timestamp": sns['Timestamp'], "id": sns['MessageId'], "subject": sns['Subject'], "message": sns['Message'] }) except Exception: raise
aws-x-ray-serverless/serverless.yml
provider: name: aws runtime: python3.6 region: us-west-2 apiKeys: - aws-x-ray-serverless-api-key tracing: true iamRoleStatements: - Effect: Allow Action: - xray:PutTraceSegments - xray:PutTelemetryRecords - sns:Publish # AWS SNSをPublishする権限を追加 - dynamodb:PutItem # DynamoDBのテーブルにItemをPutする権限を追加 Resource: "*" functions: hello: ... # AWS SNSをトリガーに実行されるLambdaを追加 putHello: handler: handler.put_hello events: - sns: hello # DynamoDBのテーブルを追加 resources: Resources: helloLogTable: Type: 'AWS::DynamoDB::Table' Properties: TableName: hello_log AttributeDefinitions: - AttributeName: timestamp AttributeType: S KeySchema: - AttributeName: timestamp KeyType: HASH ProvisionedThroughput: ReadCapacityUnits: 2 WriteCapacityUnits: 1
気づきましたでしょうか?
AWS LambdaでのAWS SNSやDynamo DBの呼び出しをトレースすると聞くといろいろな設定が必要そうと感じますが、
実際にX-Rayの適用として追加で記述したのは、
- patch_all()
だけ。
これだけでAWS SNSやDynamo DBを呼び出すboto3などのライブラリにX-Ray用のパッチが適用されてトレースが出来るようになります。
この手軽さは正直異常ですね(^^;
実際に再度デプロイコマンドを実行して、curlコマンドやRestClientなどでAPI Gatewayを呼び出してみます。
sls deploy curl -s 【API GatewayのURl】 -H "x-api-key:【APIキー】"
結果、AWSコンソールのX-RayのサービスにてAWS SNSやDynamoDBへのフローも表示されるようになりました。
Service Mapの下段にあるClientはAPI Gatewayを通してAWS Lambda、そしてAWS SNSを呼び出しており、次のトリガーとなっています。
上段のClientがそのAWS SNSから呼び出されたことを表しており、AWS Lambdaを通してDynamo DBにエラーなくアクセスしていることが分かります。
そして、赤い枠にあるような円グラフをクリックするとサービスの所要時間をヒストグラムで確認することができます。
これにより、レスポンスとしては正常な200ステータスとなっているが、異様に時間が掛かっている場合がないかを確認することが出来ます。
さらに、Tracesの詳細を見ることでクライアント呼び出しからレスポンスまでの流れをタイムラインで見ることが出来ます。
上記で異様に時間が掛かっている場合の原因が、DynamoDBの呼び出しで時間が掛かっているのかそれ以外なのかをこれで調査することが出来ます。
実際に、Lambdaのレスポンスが異常に遅いことが発覚し調査を行った際、Tracesの詳細を見ることでDynamoDBの呼び出しに時間が掛かっていることが分かったことがありました。
その時の原因としては、あるDynamoDBのテーブルがいろんなところから呼び出されており、設定していたスループットを超過して制限が掛かっていたことが判明しました。
こういったこともX-Rayを見れば簡単に調査することが魅力的ですね。
まとめ
どうでしたでしょうか。
今回みたいに簡単な準備と実装だけでAWS X-Rayを適用することができ、AWSのさまざまなサービスの連携をトレースできます。
特にAWS SNSなどはCloudWatchでトレースするとなると、呼び出しが失敗したのか、トリガーが失敗したのかなどをそれぞれログを確認することになるため大変です。
それをAWS X-Rayを使えばちょっとの実装だけでひと目で確認できるようになります。
また、Lambdaで所要時間が異様に時間が掛かっているがその原因がどこにあるのかをCloudWatchで見ようとすると、各ログの時間を調査していく必要がありますが、
詳細なトレース結果を見ることでX-Rayで簡単に突き止めることが出来るようにもなります。
CloudWatchでのトレースで苦労した経験ある方はぜひAWS X-Rayを適用してみてください。
それでは。
Acroquest Technologyでは、キャリア採用を行っています。
- ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
- Elasticsearch等を使ったデータ収集/分析/可視化
- マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
- 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
モノリシックなアプリケーションをマイクロサービス化したいエンジニア募集! - Acroquest Technology株式会社のWeb エンジニア中途・インターンシップ・契約・委託の求人 - Wantedlywww.wantedly.com