Prompt
How do I set up an OTel collector platform for high-throughput ingestion and schema normalization across production services?
Latest observation
Here’s a practical way to set up an OpenTelemetry (OTel) Collector platform for high-throughput ingestion and schema normalization across production services.
1) Use a tiered collector architecture
For production scale, avoid sending all telemetry directly to a single central collector.
Recommended layout
- SDK / agent collectors close to workloads
- Run as:
- sidecars for stateful or sensitive workloads
- DaemonSet agents on Kubernetes nodes
- host agents for VMs
- Run as:
- Gateway collectors as centralized aggregation and processing tier
- Receive from agents
- Apply heavier processing, normalization, enrichment, routing, and buffering
- Export to backends
Why this works
- Reduces load on application services
- Limits network fan-in
- Allows horizontal scaling at each tier
- Lets you isolate failure domains
2) Separate telemetry pipelines by signal
Create distinct paths for:
- Traces
- Metrics
- Logs
Each signal has different:
- ingestion burst patterns
- storage/export latency requirements
- processing cost
Keep them in separate pipelines inside the collector and scale them independently.
3) Use OTLP everywhere
Standardize on OTLP/gRPC or OTLP/HTTP from services to collectors.
Benefits
- Consistent ingestion format
- Native support in most OTel SDKs and exporters
- Easier collector-to-collector forwarding
- Lower integration complexity
4) Put load balancing in front of collectors
For high throughput, use:
- Kubernetes Service + multiple replicas
- or a dedicated load balancer / ingress
- or the OTel Collector load balancing exporter for trace-aware sharding
Common pattern
- App SDKs export to local agent
- Agents export to gateway pool
- Gateway pool exports to backends
For traces, prefer consistent hashing / trace-based sharding so spans from the same trace land on the same backend shard when possible.
5) Scale collectors horizontally
Collectors are stateless most of the time, so scale out aggressively.
Guidance
- Start multiple replicas of gateway collectors
- Use autoscaling based on:
- CPU
- memory
- queue length / exporter retry metrics
- received spans/logs/points per second
Important
Enable backpressure-aware buffering so a slow backend doesn’t collapse ingestion.
6) Tune the collector for throughput
Key settings/plugins:
Batching
Use batch processor everywhere.
- Increases export efficiency
- Reduces per-item overhead
Memory limits
Use memory_limiter to prevent OOMs.
Queues and retries
Enable queued retry on exporters:
- bounded queues
- retry with backoff
- drop policy if necessary for non-critical signals
Example processor chain
Typical high-throughput pipeline:
memory_limiterbatchresource/attributes/transform- exporter
7) Normalize schema at the collector layer
For cross-service consistency, normalize data before it reaches observability backends.
What to normalize
- service name
- deployment environment
- cloud region / availability zone
- k8s namespace / pod / node
- HTTP attributes
- database attributes
- error/status conventions
- resource labels
Use these processors
resourceprocessor: add/overwrite resource attributesattributesprocessor: rewrite span/log/metric attributestransformprocessor: apply richer transformations and mappingsfilterprocessor: drop noisy or invalid telemetrymetricstransformprocessor: rename or aggregate metrics
8) Adopt semantic conventions consistently
Use the OTel semantic conventions as the canonical schema.
Examples
Standardize:
service.nameservice.namespacedeployment.environmentcloud.providercloud.regionk8s.cluster.name
For spans:
http.request.methodhttp.response.status_codedb.systemrpc.system
For metrics:
- Prefer OTel instrument naming and convention-compliant attributes
Benefit
This avoids backend-specific or app-specific attribute drift.
9) Add enrichment from infrastructure metadata
You’ll usually want the collector to enrich telemetry with context not present in apps.
Sources
- Kubernetes metadata
- cloud metadata
- host metadata
- service discovery labels
- config map / environment metadata
Kubernetes example
Use:
k8sattributesprocessor to attach pod, namespace, deployment, node labels
This is especially helpful for:
- service ownership
- tenant isolation
- routing by namespace/team
- debugging production incidents
10) Standardize service identity at source
A major source of schema drift is inconsistent service naming.
Enforce at deployment time
Set:
OTEL_SERVICE_NAMEOTEL_RESOURCE_ATTRIBUTES
Example:
OTEL_SERVICE_NAME=checkout-api
OTEL_RESOURCE_ATTRIBUTES=deployment.environment=prod,service.namespace=payments,cloud.region=us-east-1
Add validation
Reject or rewrite telemetry that lacks required resource fields.
11) Use transform rules for schema normalization
For example, you can:
- copy old attributes to new semantic names
- remove deprecated attributes
- map custom fields to standard fields
- normalize case or values
Example use cases
http.status_code→http.response.status_codek8s.pod.name→ resource attribute standardizationenv→deployment.environment
12) Route telemetry based on policy
Use routing to send telemetry to different backends based on:
- environment
- team
- namespace
- tenant
- signal type
- sampling rules
Example
- production errors → full-fidelity traces to tracing backend
- high-volume debug logs → cheaper log storage
- metrics → TSDB backend
- security events → SIEM
Routing can happen in the gateway collector.
13) Apply tail sampling carefully
If traces are too expensive, use tail sampling at the gateway.
Useful policies
- keep error traces
- keep slow traces
- keep traces for selected services
- probabilistic sample of the rest
Warning
Tail sampling requires buffering and state. It increases memory use and operational complexity, so deploy it only on the gateway layer, not on every agent.
14) Design for failure and overload
High-throughput platforms must degrade gracefully.
Best practices
- bounded queues
- backpressure
- timeout limits
- retry with jitter
- drop low-priority telemetry first
- isolate pipelines so logs don’t affect traces, etc.
Decide drop policy
For example:
- keep traces over logs
- keep errors over debug logs
- sample low-value high-cardinality metrics
15) Secure the pipeline
Security controls
- mTLS between services and collectors
- auth at collector endpoints
- network policies / security groups
- tenant separation
- TLS to backends
- secret management for credentials
Also consider
- attribute sanitization to prevent PII leakage
- field allowlists / denylists
- log redaction processors
16) Observe the collectors themselves
Your collector fleet is critical infrastructure.
Monitor:
- CPU / memory
- dropped spans/logs/points
- exporter queue size
- retry counts
- failed exports
- received vs exported rate
- batch sizes
- latency through the collector
Export collector self-metrics to your monitoring backend.
17) A reference deployment pattern
Kubernetes example architecture
- DaemonSet collector
- receives OTLP from local pods
- enriches with k8s metadata
- batches and forwards to gateway
- Gateway collector deployment
- horizontally scaled
- applies transform / routing / tail sampling
- exports to backend(s)
Flow
App SDK -> node/sidecar collector -> gateway collector -> observability backend
18) Sample collector config pattern
A simplified gateway config might look like this:
receivers:
otlp:
protocols:
grpc:
http:
processors:
memory_limiter:
limit_mib: 2048
spike_limit_mib: 512
check_interval: 1s
k8sattributes:
resource:
attributes:
- key: deployment.environment
value: prod
action: upsert
attributes:
actions:
- key: env
action: delete
batch:
send_batch_size: 8192
timeout: 1s
exporters:
otlp:
endpoint: backend-otel-collector:4317
tls:
insecure: false
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, k8sattributes, resource, attributes, batch]
exporters: [otlp]
metrics:
receivers: [otlp]
processors: [memory_limiter, k8sattributes, resource, attributes, batch]
exporters: [otlp]
logs:
receivers: [otlp]
processors: [memory_limiter, k8sattributes, resource, attributes, batch]
exporters: [otlp]
You’d likely extend this with:
transformfilterroutingtail_sampling- separate exporters per signal
19) Capacity planning tips
Estimate based on peak telemetry volume:
- spans/sec
- log events/sec
- metric points/sec
- average payload size
- burst factor
- retention/export latency requirements
Start with:
- extra headroom for bursts
- CPU for transformations
- memory for batching and queueing
- network throughput to backend
- test failure scenarios before production launch
20) Recommended rollout approach
- Start with a small gateway pool
- Standardize service/resource attributes
- Add k8s/cloud enrichment
- Introduce batching and memory limits
- Add routing and filtering
- Add tail sampling if needed
- Scale horizontally and validate collector metrics under load
- Tighten schema governance with transforms and validation
If you want, I can also give you:
- a production-grade Kubernetes deployment example,
- a collector config for traces/metrics/logs with schema transforms, or
- a capacity planning checklist for X spans/sec and Y logs/sec.
Brands