Skip to content
intermediatePhase 48 · Distributed Systems

Distributed Tracing

Track requests across services with Jaeger, Zipkin, or OpenTelemetry.

45m
0 problems
Topic Progress0%

Trace Context

Trace Context

Trace context propagates trace information across service boundaries.

Context Elements

Trace Context:

1. Trace ID:
   - Unique identifier for entire request
   - Same across all services

2. Span ID:
   - Unique identifier for single operation
   - Different for each service

3. Parent Span ID:
   - Link to parent operation
   - Creates hierarchy

4. Trace Flags:
   - Sampling decision
   - Debug flags

W3C Trace Context Header

Header: traceparent
Format: 00-<trace-id>-<span-id>-<trace-flags>

Example:
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01

00: version
4bf92f3577b34da6a3ce929d0e0e4736: trace ID
00f067aa0ba902b7: span ID
01: trace flags (sampled)

Propagation Example

import requests
from opentelemetry import trace
from opentelemetry.propagate import inject, extract

def service_a():
    with tracer.start_as_current_span('service_a_operation') as span:
        # Inject context into headers
        headers = {}
        inject(headers)
        
        # Call service B with context
        response = requests.get('http://service-b/api', headers=headers)

def service_b():
    # Extract context from headers
    context = extract(request.headers)
    
    with tracer.start_as_current_span('service_b_operation', context=context) as span:
        # This span is child of service_a's span
        process_request()

Context Propagation Methods

Method Description Use Case
HTTP Headers W3C traceparent REST APIs
gRPC Metadata Binary propagation gRPC services
Message Headers Custom headers Message queues
URL Query parameter Redirects

Best Practices

  1. Use W3C standard for HTTP
  2. Propagate context across all boundaries
  3. Don't break the chain
  4. Sample consistently
  5. Handle missing context gracefully

Span Hierarchy

Span Hierarchy

Span Structure

Trace: abc123

Span 0: api-gateway (180ms)
├── Span 1: auth-service (20ms)
├── Span 2: order-service (150ms)
│   ├── Span 3: validate-order (10ms)
│   ├── Span 4: inventory-service (50ms)
│   │   └── Span 5: db-query (30ms)
│   ├── Span 5: payment-service (70ms)
│   │   └── Span 6: stripe-api (60ms)
│   └── Span 7: db-insert (15ms)

Span Attributes

from opentelemetry import trace

tracer = trace.get_tracer(__name__)

with tracer.start_as_current_span('process_order') as span:
    # Set attributes
    span.set_attribute('order.id', '123')
    span.set_attribute('order.amount', 99.99)
    span.set_attribute('user.id', '456')
    
    # Add events
    span.add_event('validation_started')
    validate_order()
    span.add_event('validation_completed')
    
    # Set status
    span.set_status(trace.StatusCode.OK)

Span Kinds

Kind Description Example
INTERNAL Within service Business logic
SERVER Incoming request HTTP server
CLIENT Outgoing request HTTP client
PRODUCER Message producer Kafka producer
CONSUMER Message consumer Kafka consumer

Span Timing

Span Timeline:

|←─────── Parent Span ────────→|
     |←── Child 1 ──→|
                       |←── Child 2 ──→|
                              |←─ Grandchild ─→|

Start time: When operation begins
End time: When operation completes
Duration: End - Start

Best Practices

  1. Name spans by operation
  2. Add meaningful attributes
  3. Record errors in spans
  4. Keep span depth reasonable
  5. Don't over-instrument

Jaeger and Zipkin

Jaeger and Zipkin

Jaeger

Jaeger Architecture:

Agent → Collector → Query → Storage
  ↑                     ↓
Services              UI

- Open source (Uber)
- OpenTelemetry native
- Adaptive sampling

Jaeger Implementation

from jaeger_client import Config
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.exporter.jaeger.thrift import JaegerExporter

# Setup Jaeger
jaeger_exporter = JaegerExporter(
    agent_host_name='localhost',
    agent_port=6831,
)

# Create tracer
provider = TracerProvider()
processor = BatchSpanProcessor(jaeger_exporter)
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)

tracer = trace.get_tracer(__name__)

Zipkin

Zipkin Architecture:

Reporter → Collector → Storage → API → UI
  ↑                              ↓
Services                       Query

- Open source (Twitter)
- Simple setup
- B3 propagation

Zipkin Implementation

from opentelemetry.exporter.zipkin import ZipkinExporter

zipkin_exporter = ZipkinExporter(
    endpoint='http://localhost:9411/api/v2/spans'
)

provider = TracerProvider()
processor = BatchSpanProcessor(zipkin_exporter)
provider.add_span_processor(processor)

Comparison

Feature Jaeger Zipkin
Origin Uber Twitter
OpenTelemetry Native Supported
Sampling Adaptive Rate-based
Storage Cassandra, ES Cassandra, ES, MySQL
UI Feature-rich Simple
Complexity Higher Lower

When to Use

Scenario Recommendation
OpenTelemetry native Jaeger
Simple setup Zipkin
Adaptive sampling Jaeger
Existing infrastructure Match existing

Best Practices

  1. Start with Jaeger or Zipkin
  2. Use OpenTelemetry SDK
  3. Implement adaptive sampling
  4. Monitor trace storage
  5. Set retention policies

Practice Problems

0/3solved
Design Distributed Tracing System

Design a scalable Distributed Tracing system. Cover high-level architecture, data model, and API design.

Solution
// Complete system design:
// - Functional + Non-functional requirements
// - Capacity estimation
// - Data model (SQL/NoSQL choice)
// - API endpoints
// - Component architecture
// - Scaling strategy
// - Monitoring & reliability
Distributed Tracing Scaling

How would you scale Distributed Tracing to handle 10x the current load? Identify bottlenecks and solutions.

Solution
// Scaling approach:
// 1. Load balancing
// 2. Database sharding/replication
// 3. Cache layer (Redis)
// 4. CDN for static assets
// 5. Async processing (queues)
// 6. Microservices decomposition
Distributed Tracing Failure Modes

Analyze potential failure modes for Distributed Tracing and design mitigation strategies.

Solution
// Failure mitigation:
// 1. Redundancy (multi-AZ)
// 2. Circuit breakers
// 3. Retry with backoff
// 4. Dead letter queues
// 5. Health checks
// 6. Graceful degradation

Quiz

1. What is trace context?

Question 1 options

2. What is a span in distributed tracing?

Question 2 options

3. What is the W3C traceparent header format?

Question 3 options

4. What is span hierarchy?

Question 4 options

5. Jaeger vs Zipkin: Key difference?

Question 5 options

Flashcards

Question

What is trace context?

Answer

Trace ID, span ID, and flags propagated across services via headers (W3C traceparent)

Question

What is a span?

Answer

Single operation within a trace with start time, end time, attributes, and parent span ID

Question

Span hierarchy?

Answer

Parent-child relationships between spans, creating a tree of operations in a trace

Question

Jaeger vs Zipkin?

Answer

Jaeger: OpenTelemetry native, adaptive sampling. Zipkin: simpler setup, B3 propagation.

Question

W3C traceparent format?

Answer

00-<trace-id>-<span-id>-<trace-flags> (version-trace-span-flags)

Revision Notes

Key Takeaways

  • 1.Trace context propagates across services via W3C traceparent header
  • 2.Spans represent individual operations with parent-child hierarchy
  • 3.Jaeger and Zipkin are popular tracing systems
  • 4.Use OpenTelemetry SDK for vendor-neutral instrumentation
  • 5.Propagate context across all service boundaries

Interview Tips

  • Explain trace context and propagation
  • Describe span hierarchy with example
  • Compare Jaeger vs Zipkin
  • Discuss sampling strategies

Cheat Sheet

Cheat Sheet: Distributed Tracing

Trace Context

  • Trace ID: Unique per request
  • Span ID: Unique per operation
  • Parent Span ID: Hierarchy
  • Trace Flags: Sampling

W3C Header

traceparent: 00---

Span Hierarchy

  • Parent-child relationships
  • Attributes: Key-value metadata
  • Events: Timestamped markers
  • Status: OK/Error

Tools

  • Jaeger: OpenTelemetry native
  • Zipkin: Simple setup
  • Both: Cassandra, Elasticsearch

Best Practices

  • Use W3C standard
  • Propagate context
  • Name spans by operation
  • Add meaningful attributes