Technology

Distributed Tracing Interview Preparation

distributed tracing interview preparation
Distributed Tracing Interview Preparation | SiamCafe Blog
2025-08-24· อ. บอม — SiamCafe.net· 10,013 คำ

Distributed Tracing Interview

Distributed Tracing Interview Preparation OpenTelemetry Jaeger Span Trace Context Propagation Sampling Observability Microservices Production

Conceptคำอธิบายตัวอย่างInterview Tip
TraceRequest ทั้งหมดข้าม ServicesUser → API → DB → Cacheอธิบาย Tree Structure
SpanUnit of Work ใน 1 ServiceHTTP Handler, DB QueryParent-Child Relationship
Context Propagationส่ง Trace ID ข้าม ServiceW3C traceparent Headerอธิบาย Header Format
Samplingเลือก Trace ที่จะเก็บHead-based vs Tail-basedTrade-off Cost vs Coverage
Instrumentationเพิ่ม Tracing ใน CodeAuto vs ManualOTel SDK Auto-instrumentation

OpenTelemetry Implementation

# === OpenTelemetry Python Setup ===

# pip install opentelemetry-api opentelemetry-sdk
# pip install opentelemetry-instrumentation-flask
# pip install opentelemetry-instrumentation-requests
# pip install opentelemetry-exporter-otlp

# from opentelemetry import trace
# from opentelemetry.sdk.trace import TracerProvider
# from opentelemetry.sdk.trace.export import BatchSpanProcessor
# from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
# from opentelemetry.sdk.resources import Resource
# from opentelemetry.instrumentation.flask import FlaskInstrumentor
# from opentelemetry.instrumentation.requests import RequestsInstrumentor
#
# # Setup
# resource = Resource.create({
#     "service.name": "order-service",
#     "service.version": "1.2.0",
#     "deployment.environment": "production",
# })
#
# provider = TracerProvider(resource=resource)
# exporter = OTLPSpanExporter(endpoint="http://otel-collector:4317")
# provider.add_span_processor(BatchSpanProcessor(exporter))
# trace.set_tracer_provider(provider)
#
# # Auto-instrumentation
# FlaskInstrumentor().instrument()
# RequestsInstrumentor().instrument()
#
# # Manual Span
# tracer = trace.get_tracer(__name__)
# with tracer.start_as_current_span("process_order") as span:
#     span.set_attribute("order.id", "12345")
#     span.set_attribute("order.total", 99.99)
#     result = process(order)
#     if result.error:
#         span.set_status(trace.StatusCode.ERROR, result.error)

from dataclasses import dataclass

@dataclass
class OTelComponent:
    component: str
    role: str
    config: str
    interview_point: str

components = [
    OTelComponent("SDK (TracerProvider)",
        "สร้างและจัดการ Traces ใน Application",
        "Resource + SpanProcessor + Exporter",
        "อธิบาย Pipeline: SDK → Processor → Exporter"),
    OTelComponent("Auto-instrumentation",
        "เพิ่ม Tracing อัตโนมัติ ไม่ต้องแก้ Code",
        "FlaskInstrumentor RequestsInstrumentor",
        "ลด Developer Effort ครอบคลุม HTTP DB gRPC"),
    OTelComponent("Collector",
        "Gateway รับ Process ส่งต่อ Telemetry",
        "Receivers → Processors → Exporters Pipeline",
        "อธิบาย Collector Pipeline Architecture"),
    OTelComponent("Exporter",
        "ส่งข้อมูลไป Backend (Jaeger/Tempo)",
        "OTLP gRPC/HTTP Jaeger Zipkin",
        "OTLP เป็นมาตรฐาน ไม่ Lock-in"),
    OTelComponent("Propagator",
        "ส่ง Context ข้าม Service",
        "W3C TraceContext B3 (Zipkin)",
        "traceparent: 00-traceid-spanid-flags"),
]

print("=== OTel Components ===")
for c in components:
    print(f"  [{c.component}] {c.role}")
    print(f"    Config: {c.config}")
    print(f"    Interview: {c.interview_point}")

Interview Questions & Answers

# === Interview Q&A ===

@dataclass
class InterviewQA:
    question: str
    short_answer: str
    deep_answer: str
    follow_up: str

questions = [
    InterviewQA("Trace vs Span ต่างกันอย่างไร",
        "Trace = Request ทั้งหมด, Span = Unit of Work ใน 1 Service",
        "Trace มี Trace ID เดียว ประกอบด้วยหลาย Spans Span มี Span ID Parent Span ID สร้าง Tree Structure Root Span คือ Entry Point Child Span คือ Downstream Calls",
        "Span Events vs Span Links ต่างกันอย่างไร"),
    InterviewQA("Context Propagation ทำงานอย่างไร",
        "ส่ง Trace ID + Span ID ผ่าน HTTP Header",
        "W3C traceparent: 00-{trace-id}-{parent-span-id}-{flags} Inject ตอนส่ง Request Extract ตอนรับ Request SDK จัดการอัตโนมัติ ต้อง Configure Propagator ให้ตรงกันทุก Service",
        "ถ้า Service ไม่รองรับ W3C จะทำอย่างไร (B3 Fallback)"),
    InterviewQA("Head-based vs Tail-based Sampling",
        "Head ตัดสินใจต้น Trace, Tail ตัดสินใจท้าย Trace",
        "Head-based: ง่าย ใช้ Resource น้อย ลด Traffic ตั้งแต่ต้น แต่ Miss Error/Slow Traces Tail-based: เก็บทุก Trace ใน Buffer ตัดสินใจหลังจบ เก็บ Error/Slow Traces ได้ แต่ใช้ Resource มาก ต้องมี Collector ที่แข็ง",
        "Probability Sampling vs Rate Limiting vs Always On"),
    InterviewQA("Tracing Overhead เท่าไหร่",
        "1-5% CPU/Latency ขึ้นกับ Sampling Rate และ Span จำนวน",
        "Overhead มาจาก Context Creation Attribute Setting Serialization Network I/O ลดด้วย Sampling ลด Span จำนวน ใช้ BatchSpanProcessor Async Export ใช้ Collector แยก Processing ออกจาก App",
        "วิธีวัด Tracing Overhead จริง (Benchmark)"),
    InterviewQA("Traces กับ Logs เชื่อมกันอย่างไร",
        "ใส่ Trace ID ใน Log เชื่อม Trace กับ Log Entry",
        "OTel SDK inject Trace ID Span ID ใน Log Context ใช้ Log Correlation ดู Log ของ Trace เดียวกัน Structured Logging JSON + trace_id field Query: trace_id=xxx ดู Logs ทั้ง Trace",
        "Exemplars คืออะไร (Metric → Trace Link)"),
]

print("=== Interview Q&A ===")
for q in questions:
    print(f"\n  Q: {q.question}")
    print(f"  A (Short): {q.short_answer}")
    print(f"  A (Deep): {q.deep_answer}")
    print(f"  Follow-up: {q.follow_up}")

Architecture & Production

# === Production Tracing Architecture ===

@dataclass
class ArchComponent:
    layer: str
    tool: str
    config: str
    scaling: str

architecture = [
    ArchComponent("Application Layer",
        "OTel SDK + Auto-instrumentation",
        "Resource Attributes + Sampling + BatchProcessor",
        "ทุก Service ใช้ OTel SDK เดียวกัน"),
    ArchComponent("Collection Layer",
        "OTel Collector (Gateway Mode)",
        "Receivers: OTLP → Processors: Batch/Filter → Exporters: OTLP",
        "Horizontal Scale Collector ตาม Traffic"),
    ArchComponent("Storage Layer",
        "Jaeger + Elasticsearch / Grafana Tempo + S3",
        "Retention 7-14 วัน Index Optimization",
        "Tempo + S3 ถูกกว่า Jaeger + ES 5-10x"),
    ArchComponent("Query Layer",
        "Jaeger UI / Grafana",
        "Search by Trace ID Service Name Duration",
        "Grafana เชื่อม Traces Metrics Logs ใน UI เดียว"),
    ArchComponent("Alerting Layer",
        "Grafana Alerting / PagerDuty",
        "P99 Latency > 500ms Error Rate > 1%",
        "Alert on Trace Metrics ไม่ใช่ Individual Traces"),
]

print("=== Production Architecture ===")
for a in architecture:
    print(f"  [{a.layer}] {a.tool}")
    print(f"    Config: {a.config}")
    print(f"    Scaling: {a.scaling}")

เคล็ดลับ

Distributed Tracing คืออะไร

ติดตาม Request ข้าม Services Trace ID Span Parent-Child Tree Bottleneck Error Dependencies Jaeger Zipkin Tempo OpenTelemetry W3C

OpenTelemetry คืออะไร

Observability Framework CNCF Traces Metrics Logs SDK Auto-instrumentation Collector Exporter Propagator Semantic Conventions OTLP

คำถามสัมภาษณ์มีอะไร

Trace vs Span Context Propagation Head Tail Sampling Overhead 1-5% Log Correlation Baggage High Cardinality Exemplars

Production Best Practices มีอะไร

OTel SDK Auto-instrumentation Sampling 10% Collector Gateway Tempo S3 Alert P99 Latency Error Rate Correlate Traces Metrics Logs

สรุป

Distributed Tracing Interview OpenTelemetry Jaeger Tempo Span Context Propagation Sampling Collector Observability Production

📖 บทความที่เกี่ยวข้อง

DNS over TLS Interview Preparationอ่านบทความ → Whisper Speech Interview Preparationอ่านบทความ → Stencil.js Interview Preparationอ่านบทความ → Distributed Tracing Zero Downtime Deploymentอ่านบทความ → Java Micronaut Interview Preparationอ่านบทความ →

📚 ดูบทความทั้งหมด →