AWS X-Ray in Distributed Microservices — Part 1: Setup
AWS X-Ray is an AWS managed service that helps to visualize, analyze and debug distributed applications.
You do need some code changes to use AWS X-Ray; however, with tiny changes, you could enable a lot of visibility and traceability in your application.
In this blog, I’ll show how easy is to start using AWS X-Ray and how it could help in a couple of tricky scenarios.
Concepts
A very brief overview of AWS X-Ray concepts.
Service graph
Service graph or map is a visual representation for your application. Each resource is shown as a node in a graph.
Segment
Is a representation of a logical compute resource in the application.
Subsegment
A further break down of the data with more granular timing information and details about the call.
Traces
Each trace id
represents a path that a particular request uses to go through an application
Setup
AWS X-ray can trace different types of requests:
- API Gateway requests
- http(s) calls from the application
- AWS SDK calls
- DB queries
- Custom segments/subsegments
I’ve found that the first four are the easiest to implement and give a lot of useful information about the distributed application. In many scenarios adding those is enough to have sufficient visibility on how an application is used.
Using the first four types, AWS X-Ray shows the architecture and propagation of requests within microservices.
As you will see, with just a few lines of code we can cover most of the actions done by a regular cloud-based web application.
AWS X-Ray wrappers
AWS X-Ray uses wrappers to instrument the calls and supports multiple languages: Go, Java, Node.js, Python, Ruby, .NET.
I will be using Node.js in the examples below, but all X-Ray wrappers give similar results and experiences regardless of programming language.
AWS X-Ray daemon
AWS X-Ray Daemon is required to get raw segment data and send it to AWS X-Ray API.
AWS Lambda and AWS Elastic Beanstalk have built-in integration with X-ray and do not require a separate daemon to run.
API Gateway
AWS X-Ray tracing for API GW could be enabled with CloudFormation; however, it only supports new API Gateways and cannot be added to an existing one. If you have existing API GW with CFN template, adding TracingEnabled
would cause a failure (unless you’re happy to remove and recreate an API GW).
However, AWS Console and AWS CLI could be used for it with no issues.
aws apigateway update-stage --rest-api-id ${REST_API_ID} --stage-name ${STAGE} --patch-operations op=replace,path=/tracingEnabled,value=true
Make sure a role you’re using has the following permissions
Statement:
- Action:
- 'iam:CreateServiceLinkedRole'
Resource: !Sub 'arn:aws:iam::${AWS::AccountId}:role/aws-service-role/*'
Effect: Allow
http(s) calls from the application
AWS X-Ray could be used to trace any outcoming HTTP(s) calls. It uses a wrapper that gets a data from the call request/response and adds a tracing header with a Parent ID
to the call.
To start tracing it, your application needs two main parts:
- permissions
- aws x-ray sdk
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess"
e.g. NodeJS
const AWSXRay = require('aws-xray-sdk'); AWSXRay.captureHTTPsGlobal(require('http')); AWSXRay.captureHTTPsGlobal(require('https'));
And that's it! Place those 3 lines of code in your handler.js
and all your nested classes would be traced for outgoing http(s) calls: rest, soap etc.
If you’re using restful microservices than adding just HTTP(s) calls capture would give you quite a good picture of what your distributed system is doing and how requests get propagated. Yes, by adding 3 lines of code and the permission.
AWS SDK calls
To trace AWS SDK calls with X-Ray just use x-ray wrapper and the same permission as above.
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess"
And a wrapper
const AWS = AWSXRay.captureAWS(require('aws-sdk'));
That's all that is needed for a NodeJS application to trace AWS SDK calls with AWS X-Ray. This covers all the interaction with DynamoDB, SQS, SNS, S3, etc
DB queries
To capture Postgres or MySQL queries use the same policy
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess"
and a corresponding wrapper to create a connection
const AWSXRay = require('aws-xray-sdk’);
const pg = AWSXRay.capturePostgres(require('pg'));...const AWSXRay = require('aws-xray-sdk’);
const mysql = AWSXRay.captureMySQL(require('mysql'));
Custom subsegment.
You can create your own segments and subsegments to wrap some pieces of code and get a visual representation of it on a service map. This could be useful for some transformation or sorting withing an application to keep an eye on performance an errors.
AWSXRay.captureAsyncFunc('send', function(subsegment) {
sendRequest(host, function() {
console.log('rendering!');
res.render('index');
subsegment.close();
});
});
Conclusion
A number of times I’ve heard concerns that AWS X-Ray requires significant code changes and is not that easy to setup.
Hopefully, in this article, I was able to show how quick and simple is to get a lot of value by using AWS X-Ray in a common cloud application to cover scenarios like current architecture, outgoing HTTP calls, DB queries, and AWS SDK usage.
Use cases and my experience of using AWS X-Ray in production applications are expressed in “AWS X-Ray in Distributed Microservices — Part 2: Use cases”