8 views
At 50k RPS, 100% traces are not observability — they are a denial-of-wallet attack against your collector. Head sampling alone drops errors you needed; no sampling melts X-Ray/OTLP exporters and Node event loops under protobuf encode. The unfair advantage is layered policy: low head sample for success, guaranteed keep for errors/high latency via tail sampling (or parent-based rules), and exporter backpressure that sheds before the API does.
⚡ TL;DR: Start with parent-based head sampler at 1–5% for healthy traffic; force-sample error and >p99 latency traces; run a tail sampler (Gateway/collector) for final decisions; bound queue + batch in the Node SDK. Pair with OpenTelemetry Tail Sampling and OpenTelemetry for LLMs.
OpenTelemetry Sampling for Node: production guidance
typescript
// src/otel.ts
import { NodeSDK } from "@opentelemetry/sdk-node";
import { ParentBasedSampler, TraceIdRatioBasedSampler, SamplingDecision } from "@opentelemetry/sdk-trace-base";
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
class ErrorAwareRatioSampler extends TraceIdRatioBasedSampler {
// Ratio applied only when parent says "ask child"
constructor(private ratio: number) { super(ratio); }
}
const exporter = new OTLPTraceExporter({ url: process.env.OTLP_URL });
const processor = new BatchSpanProcessor(exporter, {
maxQueueSize: 2048, // ✅ bound memory
scheduledDelayMillis: 5000,
maxExportBatchSize: 512,
});
const sdk = new NodeSDK({
sampler: new ParentBasedSampler({
root: new TraceIdRatioBasedSampler(Number(process.env.TRACE_RATIO ?? "0.02")),
}),
spanProcessors: [processor],
});
sdk.start();
typescript
// ❌ AlwaysOnSampler in production at 50k RPS
import { AlwaysOnSampler } from "@opentelemetry/sdk-trace-base";
Force-keep errors at the edges
typescript
Collector sketch (tail):
// src/http-hook.ts — after response, bump sampling bit for bad outcomes
import { trace, SpanStatusCode } from "@opentelemetry/api";
export function finalizeSpan(status: number, durationMs: number) {
const span = trace.getActiveSpan();
if (!span) return;
if (status >= 500 || durationMs > 2000) {
span.setStatus({ code: SpanStatusCode.ERROR });
span.setAttribute("sampling.force", true);
// Tail sampler / collector rule keys off this attribute or status
}
}
yaml
# otel-collector-config.yaml (excerpt)
processors:
tail_sampling:
decision_wait: 10s
policies:
- name: errors
type: status_code
status_code: { status_codes: [ERROR] }
- name: slow
type: latency
latency: { threshold_ms: 2000 }
- name: probabilistic
type: probabilistic
probabilistic: { sampling_percentage: 2 }
Budget math at 50k RPS
| Assumption | Value |
|---|---|
| RPS | 50,000 |
| 2% head sample | 1,000 root traces/s |
| Spans/trace | ~8 |
| Export | ~8k spans/s — still heavy; push ratio to 0.5–1% + tail keep errors |
| Node risk | Batch encode on event loop → watch exporter drop metrics |
Closing checklist
✅ Dos – ✅ Parent-based ratio for roots; respect upstream sample flags – ✅ Tail-keep errors and slow requests – ✅ Bound BatchSpanProcessor queues; monitor drops – ✅ Separate trace pipeline SLOs from app SLOs – ✅ Load-test collectors at peak, not average ❌ Don’ts – ❌ Don’t run AlwaysOn in prod “just for a week” – ❌ Don’t sample only in the app with no collector policy – ❌ Don’t ignore exporter error/drop metrics – ❌ Don’t attach huge payloads as span attributesRelated reading
- OpenTelemetry Tail Sampling: Full Fidelity on Errors, Sparse on Success
- OpenTelemetry for LLMs: Trace Prompt Latency Across Microservices
- Lambda X-Ray Sampling: Cost Versus Debuggability During Incidents
- Node Diagnostic Channels: Instrument Hot Paths Without Monkey Patches
Watch: 100 Days of AI on YouTube
Short videos from CheatCoders, one AI engineering topic per day.
Most viewed
- Python Decorators Explained: From Simple Wrappers to Production Patterns
- Claude Code vs Cursor vs GitHub Copilot: Choose by Workflow, and Set Up One Repo That Works With All Three
- AI Agent Frameworks in 2025: LangGraph vs CrewAI vs AutoGen vs Raw API
- Python String Methods: Every str Method With Real Production Examples
- Css Animation Performance: Performance-Optimized Motion for Modern UIs
Newly added
- AWS Systems Manager Parameter Store: Hierarchical Runtime Config for Coding Agents
- Amazon Cognito Identity Pools: Federate Coding-Agent Tool Callers Without Long-Lived Keys
- Amazon Athena for Coding Agents: Query Tool Audit Logs and Eval Traces on S3 Without a Warehouse
- AWS Batch for Coding Agents: Parallel Overnight PR Reviews and Long-Running Jobs Without Lambda Timeouts
- Amazon Bedrock Prompt Management: Version and A/B Test Coding-Agent System Prompts
Deep-dive PDF
Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.
Already subscribed? or open the subscribe page.
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.
