[AWS] X-Ray
X-ray๋ AWS์์ ์ ๊ณตํ๋ Trace ์์ง ๋ฐ ๊ด๋ฆฌ ์์คํ
์ด๋ค.
API ๋จ์ ๊ฐ์ ๊ฐ๋ณ Trace(Transaction) ๋จ์์ ๊ด์ธก์ ์ธ๋ถ APM ์์ด AWS ๋ด์์ ์์ฒด์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์๊ฒ ํด์ค๋ค.
์ด๋ฐ๊ฑฐ๋ค.
๊ทธ๋ฆฌ๊ณ OpenTelemetry ๊ธฐ๋ฐ์ผ๋ก ๋ง๋ค์ด์ง ๊ฑฐ๋ผ์, ๋ค๋ฅธ Otel ๋๊ตฌ๋ค๊ณผ ์ด๋ ์ ๋ ํธํ๋๋ค.
๋น์ฉ
๊ฐ๊ฒฉ์ ๊ทธ๋ฅ ์ ๋นํ ํธ์ด๋ค. DataDog ๊ฐ์ ๊ฐ๋๋ค์ ๋นํ๋ฉด ์ธ๊ณ , ์ง์ ๊ตฌ์ถํด์ ์ฐ๋ ๊ฒ์ ๋นํ๋ฉด ๋น์ธ๋ค.
https://aws.amazon.com/ko/cloudwatch/pricing/
๊ธฐ๋ก ๊ด์ ์์ ๋ณด๋ฉด 100๋ง๊ฐ๋น $5๊ฐ ๋๊ฐ๋ค. Trace๊ฐ ๋ง๋ค๋ฉด ๊ธ๋ฐฉ ๋น์ฉ์ด ๋์ด๋ ๊ฒ์ด๋ค.
๋ฌด๋ฃ ์ฌ์ฉ๋๋ ์ข ์๋ค.
๊ธฐ๋ณธ
์ฝ์์์ X-ray๋ฅผ ํ์ธํ๋ ค๋ฉด Cloudwatch ์น์ ์ ํ์ ํญ์ผ๋ก ๋ณผ ์ ์๋ค.

๊ทธ๋ฆฌ๊ณ ์ X-ray ๊ทธ๋ฃน์ ์ต์์ ํํฐ ๋จ์๋ผ๊ณ ํ ์ ์๋ค. ๋ณดํต ์๋น์ค ์ด๋ฆ ๊ฐ์๊ฑธ ์ ๊ธฐ์ ๋ฐ๋๋ฐ, ์ด๊ฑด AWS CLI๋ฅผ ํตํด ๋ง๋ค์ด์ค์ผ ํ๋ค.
aws xray create-group \
--region ap-northeast-2 \
--group-name just-test-api \
--filter-expression 'service("just-test-api")'

์ฑ ์์ด์ ํธ ๊ตฌ์ฑ (docker compose)
์ฑ์์ Trace๋ฅผ ์ ์ฌํ๊ฒ ํ๋ ค๋ฉด ์ ์ฉ Otel SDK๋ฅผ ๋ถ์ด๋ ๊ฒ์ด ๊ถ์ฅ๋๋ ๋ฐฉ๋ฒ์ด๋ค.
X-ray ์ ์ฉ ์์ด์ ํธ ๊ตฌ์ฑ์ด ์๊ธด ํ๋ฐ, deprecated๋ ์ํ๋ผ์ ๊ถ์ฅํ์ง ์๋๋ค.
๋จผ์ otel collector๋ฅผ ์ ์ํ๋ค. ์ด๊ฒ x-ray๋ฅผ ๋ณด๋ด๋ ์ฑ
์์ ๊ฐ์ง๋ค.
config ํ์ผ์ ๋ง๋ค๊ณ
vim otel-collector-config.yamlreceivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch/traces:
exporters:
awsxray:
region: ${env:AWS_REGION}
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch/traces]
exporters: [awsxray]
์ด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก otel collector๋ฅผ ์ ์ํ๋ค.
services:
...
adot-collector:
image: public.ecr.aws/aws-observability/aws-otel-collector:latest
command: ["--config=/etc/otel-agent-config.yaml"]
environment:
AWS_PROFILE: ${AWS_PROFILE:-...-dev}
AWS_REGION: ${AWS_REGION:-ap-northeast-2}
AWS_CONFIG_FILE: /home/aoc/.aws/config
AWS_SHARED_CREDENTIALS_FILE: /home/aoc/.aws/credentials
volumes:
# ADOT image runs as the non-root `aoc` user (HOME=/home/aoc).
- ${HOME}/.aws:/home/aoc/.aws:ro
- ./otel-collector-config.yaml:/etc/otel-agent-config.yaml:ro
ports:
- "4317:4317"
- "4318:4318"
restart: unless-stopped
๊ทธ๋ฆฌ๊ณ ๋ฉ์ธ ์ฑ์์๋ otel collector์ ๊ฒฝ๋ก๋ก ์ฐ๋ฌ์ trace๋ฅผ ๋ ๋๊ธฐ๋ฉด ๋๋ค.
๋ค์์ node.js/express์ ๊ตฌ์ฑ ์์๋ค.
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { AWSXRayIdGenerator } from '@opentelemetry/id-generator-aws-xray';
import { AWSXRayPropagator } from '@opentelemetry/propagator-aws-xray';
export const telemetrySdk = new NodeSDK({
serviceName: process.env.OTEL_SERVICE_NAME ?? 'just-test-api',
traceExporter: new OTLPTraceExporter({
url: process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
?? 'http://localhost:4318/v1/traces',
}),
idGenerator: new AWSXRayIdGenerator(),
textMapPropagator: new AWSXRayPropagator(),
instrumentations: [getNodeAutoInstrumentations()],
});
telemetrySdk.start();
์ธ์ด๋ณ ๊ตฌ์ฑ๋ฐฉ๋ฒ ๋ฑ์ ๋ณ๋ ๋ฌธ์๋ฅผ ์ฐธ์กฐํ๋ค.
https://aws-otel.github.io/docs/introduction
๊ทธ๋ฆฌ๊ณ ์คํํด์ ๋๋ ค๋ณด๋ฉด
์ด๋ฐ ์์ผ๋ก Trace๊ฐ ์๋ฉ ์์ผ ๊ฒ์ด๋ค.
Trace ์์ธ ๋ฒํผ์ ๋๋ฌ์ ๋ค์ด๊ฐ๋ฉด ์ด๋ฐ์ ๋ฐ ์ ๋ณด๋ค์ ๋ณผ ์ ์๋ค.
ํ์ Span ๋จ์ ๋ ์ดํด์ & ์ํ ์ ๋ณด๋ ๋ณผ ์ ์๊ณ
๋ฉํ๋ฐ์ดํฐ ๊ฐ๋ค๋ ๊ด์ธก์ด ๋๋ค.
์๋จ ํญ์์๋ ์์ฑ๋ณ ํต๊ณ๊ฐ์ ๋น ๋ฅด๊ฒ ์ฐ์ด๋ณผ ์๋ ์๋ค.


Trace Map
Trace๋ฅผ ์์ผ๋ฉด, ์ธํ
๋ ์์ฑ๊ฐ๋ค ๊ธฐ์ค์ผ๋ก ์๋น์ค๊ฐ ์ฐ๊ฒฐ ๊ด๊ณ๋ฅผ ๋์ํํด์ ๋ณผ ์ ์๋ค.
Trace Map ํญ์ผ๋ก ๋ค์ด๊ฐ๋ฉด ๋๋ค.

Error ํธ๋ค๋ง
๋ค๋ฅธ Otel ๋๊ตฌ๋ค๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก, ์ค๋ฅ๋ฅผ Trace์ ํ์ ์์ฑ์ผ๋ก ํํํ๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ์ ๊ณต๋๋ ๋ฏธ๋ค์จ์ด์์ Error๊ฐ ๋จ์ด์ง๋ฉด ์๋ฌ๋ก ์ฒ๋ฆฌ๋ฅผ ์์์ ํด์ฃผ๋๋ฐ, ์ํ๋ค๋ฉด ์๋์ผ๋ก ์๋ฌ๋ฅผ ์บก์ณํ ์๋ ์๋ค.
์๋ฌดํผ ์ค๋ฅ๋ฅผ ๋ฐ์์์ผ๋ณด๋ฉด

์ค์ ๋ก Trace๊ฐ ์๋ฌ ์ํ๋ก ๊ธฐ๋ก๋ ๊ฒ์ด๋ค.

์ด ์์ฒด๋ก ํน๋ณํ ๊ฒ์ ๋ณ๋ก ์๋ค. ์ค๋ฅ๋ผ๋ ์ํ๊ฐ์ด ๋ฌ๋ผ์ง ๋ฟ์ด๋ค.
์ฝ์์์ ์ค๋ฅ๋ง ๊ฒ์ํด์ ๋ณด๋ ค๋ฉด ์ด๋ ๊ฒ ์กฐ๊ฑด์ ์ฃผ๋ฉด ๋๋ค.

์ฐธ์กฐ
https://docs.aws.amazon.com/ko_kr/xray/latest/devguide/aws-xray.html
https://docs.aws.amazon.com/ko_kr/xray/latest/devguide/xray-concepts.html
https://docs.aws.amazon.com/ko_kr/xray/latest/devguide/xray-gettingstarted.html