OpenTelemetry i produktion: Sluta felsöka i mörker
· 4 min read · Filippo Spinella · Observability, Node.js, DevOps, Backend
Första gången du verkligen behöver observerbarhet är inte när du lugnt tittar på en instrumentpanel. Det är när en användare skriver "utcheckningen är långsam", feldiagrammet ser normalt ut och i loggarna hittar du bara en rad med frånkopplade meddelanden.
OpenTelemetry skapades för att undvika det ögonblicket: inte för att ha mer grafik, utan för att koppla ihop bitarna. En begäran går in i API, anropar en databas, går via en extern leverantör, lägger upp ett köat jobb och misslyckas kanske tre tjänster senare. Utan distribuerad spårning rekonstruerar du den historien för hand. Med OpenTelemetry har du åtminstone en karta.
Poängen är inte trace, det är historien
En trace är en sekvens av span. Satt så låter det kallt. I praktiken är varje span en del av berättelsen: POST /checkout, SELECT inventory, call payment provider, publish order.created.
Värdet kommer när du börjar svara på riktiga frågor:
- vilken extern tjänst saktar ner?
- kommer felen från en specifik version? – drabbar problemet alla eller bara en hyresgäst?
- döljer ett nytt försök en timeout?
- det asynkrona jobbet börjar men dör sedan någon annanstans?
Dessa frågor kan inte lösas genom att en console.log kastas i en hast. Faktum är att ofta loggen som läggs till i en nödsituation hjälper dig idag och blir till buller i morgon.
Hur skulle jag lägga detta i en app Node.js
Den hälsosammaste installationen är enkel: appen producerar telemetri, Collector bestämmer vart den ska skickas.
Node.js app -> OpenTelemetry Collector -> backend di observability
Varför inte exportera direkt till leverantören? För till en början verkar det snabbare, sedan inser du att varje tjänst har olika konfigurationer, olika försök, olika filter och ingen central punkt för att ta bort känslig data eller byta destination.
Collector är tråkigt på alla de rätta sätten. Den tar emot OTLP, gör batchning, kan filtrera, kan göra sampling, kan lägga till vanliga attribut och kan exportera till flera system.
Självinstrumentering: bra, men inte tillräckligt
I Node.js skulle jag börja med autoinstrumentering. Det ger dig omedelbar insyn i HTTP, ramverk som stöds, databaser och vanliga bibliotek.
npm install @opentelemetry/sdk-node \ @opentelemetry/auto-instrumentations-node \ @opentelemetry/exporter-trace-otlp-http
Sedan initierar du SDK före resten av appen:
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();
Detta ser dock ramverket, inte din produkt. Den vet att du gjorde en fråga, men den vet inte att frågan var i "skapa ordning" eller "förnya prenumeration". För det behöver du span manualer på de punkter där dominans räknas.
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(); }
Jag skulle inte lägga span manualer någonstans. Jag skulle lägga dem där jag klockan tre på morgonen skulle vilja förstå vad som hände utan att läsa halva kodbasen.
Tre regler som undviker mycket kaos
Första regeln: varje tjänst måste ha service.name, miljö och version. Det verkar trivialt, men utan dessa attribut är en trace mycket mindre användbar. När en distribution bryter något vill du filtrera efter version på två sekunder.
Andra regeln: lägg inte känslig information i attributen. E-postmeddelanden, tokens, heltalsnyttolaster och adresser bör inte hamna i en observerbar backend av misstag. Om du behöver identifiera en användare, överväg interna ID:n, hashing eller mindre känsliga fält.
Tredje regeln: var uppmärksam på kardinalitet. user.id som ett attribut för trace kan vara vettigt. Som en metrisk etikett kan den förstöra dina kostnader och prestanda.
Mätvärden: få, men bra
Jag skulle börja med mycket praktiska mått:
- antal, fel och varaktighet för förfrågningar.
- latens för externa beroenden;
- antal timeouts och omförsök;
- djupet på svansarna;
- jobbets varaktighet;
- procentandel av fel per version.
Resten tillsätts vid behov. Instrumentpaneler fulla av grafer som ingen tittar på är möbler, inte observerbarhet.
Loggar: Fortfarande användbara, men länkade
Loggar försvinner inte. De blir helt enkelt mycket mer användbara när de bär trace_id och span_id. Så du kan börja från en fellogg och öppna trace, eller börja från en långsam trace och bara läsa loggarna som skapas i den sökvägen.
Utan korrelation letar du efter nålar. Med korrelation vet du åtminstone vilken låda du ska titta i.
Checklistan jag skulle använda innan jag sa "vi är täckta"
- trace korsar faktiskt flera tjänster.
- Loggar inkluderar
trace_idochspan_id. - Collector är konfigurerad med batch- och minnesgränser.
- Fel registreras i span. – Det finns en provtagningspolicy. – Mätvärden har kontrollerat kardinalitet.
- Känsliga data filtreras.
- Varningar utgår från användarsymptom, inte slumpmässiga grafer.
Slutsats
OpenTelemetry löser inte produktionsproblem på egen hand. Men sättet du hanterar dem förändras. Istället för att blint lägga till loggar börjar du följa den faktiska sökvägen för en begäran.
För mig är tecknet på att det fungerar enkelt: när något händer slutar teamet att fråga "var letar vi?" och börjar fråga "varför är den biten långsam?". Det är där observerbarhet blir ett verktyg, inte en samling instrumentpaneler.