관찰 가능성이 처음으로 필요한 때는 침착하게 대시보드를 볼 때가 아닙니다. 사용자가 "결제가 느립니다"라고 쓰면 오류 그래프가 정상적으로 보이고 로그에는 연결이 끊긴 메시지 행만 발견됩니다.
OpenTelemetry은 그 순간을 피하기 위해 만들어졌습니다. 더 많은 그래픽을 갖기 위해서가 아니라 조각들을 연결하기 위해서였습니다. 요청은 API에 들어가고, 데이터베이스를 호출하고, 외부 공급자를 통과하고, 대기 중인 작업을 게시하고, 나중에 세 가지 서비스가 실패할 수도 있습니다. 분산 추적을 사용하지 않으면 해당 스토리를 직접 재구성할 수 있습니다. OpenTelemetry이면 최소한 지도가 있습니다.
요점은 trace가 아니라 이야기입니다
A trace는 span의 시퀀스입니다. 그렇게 말하면 차갑게 들릴 것 같아요. 실제로 각 span는 이야기의 일부입니다: POST /checkout, SELECT inventory, call payment provider, publish order.created.
실제 질문에 답하기 시작할 때 가치가 나타납니다.
- 어떤 외부 서비스가 느려지나요?
- 특정 버전에서 오류가 발생합니까?
- 문제가 모든 사람에게 영향을 미치나요, 아니면 한 명의 세입자에게만 영향을 미치나요?
- 재시도가 시간 초과를 숨기고 있습니까?
- 비동기 작업이 시작되었지만 다른 곳에서 종료됩니까?
이 질문은 서둘러 console.log를 던지는 것으로는 해결될 수 없습니다. 실제로 긴급 상황에 추가된 로그가 오늘은 도움이 되지만 내일은 소음이 되는 경우가 많습니다.
이것을 앱에 어떻게 넣으나요 Node.js
가장 건전한 설정은 간단합니다. 앱이 원격 측정을 생성하고 Collector가 이를 보낼 위치를 결정합니다.
Node.js app -> OpenTelemetry Collector -> backend di observability
공급업체에 직접 수출하지 않는 이유는 무엇입니까? 처음에는 더 빨라 보이기 때문에 각 서비스에는 서로 다른 구성, 서로 다른 재시도, 서로 다른 필터가 있고 중요한 데이터를 제거하거나 대상을 변경하는 중앙 지점이 없다는 것을 알게 됩니다.
Collector는 모든 면에서 지루합니다. OTLP을 수신하고, 일괄 처리를 수행하고, 필터링하고, 샘플링을 수행하고, 공통 속성을 추가하고, 여러 시스템으로 내보낼 수 있습니다.
자체 계측: 좋지만 충분하지 않음
Node.js에서는 자동 계측부터 시작하겠습니다. HTTP, 지원되는 프레임워크, 데이터베이스 및 공통 라이브러리에 대한 즉각적인 가시성을 제공합니다.
npm install @opentelemetry/sdk-node \ @opentelemetry/auto-instrumentations-node \ @opentelemetry/exporter-trace-otlp-http
그런 다음 앱의 나머지 부분보다 먼저 SDK를 초기화합니다.
import { NodeSDK } from '@opentelemetry/sdk-node'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; const sdk = new NodeSDK({ traceExporter: new OTLPTraceExporter({ url: process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, }), instrumentations: [getNodeAutoInstrumentations()], }); sdk.start();
그러나 이는 제품이 아닌 프레임워크를 보는 것입니다. 쿼리를 했다는 것은 알지만 쿼리가 "주문 생성" 또는 "구독 갱신"에 있었는지는 알 수 없습니다. 이를 위해서는 지배력이 중요한 지점에 span 매뉴얼이 필요합니다.
const span = tracer.startSpan('checkout.create_order'); try { span.setAttribute('cart.items_count', input.items.length); const order = await createOrder(input); span.setAttribute('order.id', order.id); return order; } catch (error) { span.recordException(error as Error); throw error; } finally { span.end(); }
나는 span 매뉴얼을 어디에도 두지 않을 것입니다. 나는 코드 베이스의 절반도 읽지 않고 새벽 3시에 무슨 일이 일어났는지 이해하고 싶은 곳에 그것들을 놓을 것입니다.
많은 혼란을 피하는 세 가지 규칙
첫 번째 규칙: 각 서비스에는 service.name, 환경 및 버전이 있어야 합니다. 사소해 보이지만 이러한 속성이 없으면 trace는 훨씬 덜 유용합니다. 배포로 인해 문제가 발생하면 2초 안에 버전별로 필터링하고 싶습니다.
두 번째 규칙: 속성에 민감한 데이터를 넣지 마세요. 이메일, 토큰, 정수 페이로드 및 주소는 실수로 관측 가능성 백엔드에 포함되어서는 안 됩니다. 사용자를 식별해야 하는 경우 내부 ID, 해싱 또는 덜 민감한 필드를 고려하세요.
세 번째 규칙: 카디널리티에 주의하세요. user.id는 trace의 속성으로 이해될 수 있습니다. 측정항목 레이블로 사용하면 비용과 성능이 저하될 수 있습니다.
지표: 적지만 좋음
매우 실용적인 측정항목부터 시작하겠습니다.
- 요율, 오류 및 요청 기간
- 외부 종속성의 대기 시간
- 시간 초과 및 재시도 횟수
- 꼬리의 깊이;
- 작업 기간
- 버전당 오류 비율.
나머지는 필요할 때 추가됩니다. 아무도 보지 않는 그래프로 가득 찬 대시보드는 관측 가능성이 아니라 가구입니다.
로그: 여전히 유용하지만 링크되어 있습니다.
로그는 사라지지 않습니다. trace_id 및 span_id을 휴대하면 훨씬 더 유용해집니다. 따라서 오류 로그에서 시작하여 trace을 열거나 느린 trace에서 시작하여 해당 경로에서 생성된 로그만 읽을 수 있습니다.
상관 관계가 없으면 바늘을 찾고 있습니다. 상관관계를 통해 최소한 어떤 서랍을 들여다봐야 할지 알 수 있습니다.
"우리는 보장됩니다"라고 말하기 전에 사용할 체크리스트
- trace는 실제로 여러 서비스를 교차합니다.
- 로그에는
trace_id및span_id가 포함됩니다. - Collector는 일괄 처리 및 메모리 제한으로 구성됩니다.
- span에 오류가 기록됩니다.
- 샘플링 정책이 있습니다.
- 측정항목은 카디널리티를 제어했습니다.
- 민감한 데이터는 필터링됩니다.
- 알림은 무작위 그래프가 아닌 사용자 증상부터 시작됩니다.
결론
OpenTelemetry는 생산 문제를 자체적으로 해결하지 않습니다. 하지만 그들을 대하는 방식은 달라집니다. 맹목적으로 로그를 추가하는 대신 요청의 실제 경로를 따르기 시작합니다.
나에게 있어 이것이 작동하고 있다는 신호는 간단합니다. 어떤 일이 발생하면 팀은 "우리가 어디를 보고 있는가?"라고 묻지 않습니다. "그 작품은 왜 느린가요?"라고 묻기 시작합니다. 관찰 가능성이 대시보드 모음이 아닌 도구가 되는 곳입니다.