Distributed Tracing คืออะไร? Jaeger vs Zipkin

ในระบบ microservices หนึ่ง request ของผู้ใช้อาจวิ่งผ่าน service 5-10 ตัวก่อนได้ response กลับ — ถ้าเกิด latency สูงผิดปกติ หรือ error ขึ้นในช่วงใดช่วงหนึ่ง การไล่ดู log แยกทีละ service เป็นเรื่องยากและช้ามาก distributed tracing ถูกออกแบบมาเพื่อตอบโจทย์นี้ โดยติดตาม request ข้ามหลาย service แล้วร้อยเรียงออกมาเป็น timeline เดียวที่อ่านเข้าใจได้

บทความนี้จะอธิบายแนวคิดพื้นฐานของ distributed tracing, คำศัพท์สำคัญอย่าง trace/span/context, และเปรียบเทียบ 2 ตัวเลือกยอดนิยมในโลก open-source คือ Jaeger กับ Zipkin เพื่อให้ผู้อ่านเลือกเครื่องมือที่เหมาะกับระบบของตัวเองได้

Distributed Tracing คืออะไร

Distributed tracing คือเทคนิคการติดตาม request แบบ end-to-end ข้ามหลาย service โดยแต่ละ service จะสร้าง span หนึ่ง (หรือหลาย) span บันทึก operation ที่เกิดขึ้นในช่วงเวลาหนึ่ง — เริ่มต้น, สิ้นสุด, tag ต่าง ๆ เช่น HTTP method, status code, error message — แล้วส่ง span ทั้งหมดไปรวมที่ backend เพื่อต่อเรียงเป็น trace เดียว

แต่ละ trace จะมี trace ID เฉพาะตัวที่ส่งต่อระหว่าง service ผ่าน HTTP header (เช่น traceparent, uber-trace-id) วิธีนี้ทำให้เห็นภาพว่า request นี้ผ่าน service อะไรบ้าง, ใช้เวลาที่ขั้นไหน, และเกิดปัญหาที่จุดใด — ช่วยในการ debug performance, หาคอขวด, และวิเคราะห์ root cause ได้เร็วกว่าการดู log ทีละ service หลายเท่า

คำศัพท์สำคัญ

  • Trace — ชุดของ span ทั้งหมดของ request เดียวกัน อ่านได้เป็น timeline
  • Span — หน่วยย่อยสุด แทน operation หนึ่งเช่น HTTP call, DB query, cache lookup
  • Parent span / Child span — span ย่อยที่ถูกสร้างภายใน span พ่อ
  • Trace context — metadata (trace ID, span ID, flags) ที่ส่งระหว่าง service
  • Sampler — ตัวตัดสินว่า trace ไหนจะถูกเก็บ เพื่อลดภาระ storage
  • Tag / Attribute — key-value บน span เช่น http.method=POST, user.id=42

Jaeger — ลูกหลานของ Dapper

Jaeger เป็น distributed tracing platform ที่พัฒนาโดย Uber จากนั้นบริจาคให้ CNCF (Cloud Native Computing Foundation) เขียนด้วย Go เน้นประสิทธิภาพสูง รองรับ storage backend หลายตัว (Cassandra, Elasticsearch, Kafka) และมี UI ที่ทำงานร่วมกับ trace ขนาดใหญ่ได้ดี — ทำให้กลายเป็นตัวเลือกยอดนิยมในกลุ่ม Kubernetes และ cloud-native stack

สถาปัตยกรรมของ Jaeger แบ่งเป็น agent (เดิม) หรือ collector แบบ direct, storage, query service, และ UI การ deploy สามารถใช้ Helm chart หรือ Jaeger Operator บน Kubernetes ได้โดยตรง และยังรองรับ OpenTelemetry format ตั้งแต่ version 1.35 เป็นต้นมา

Zipkin — ต้นแบบของวงการ

Zipkin พัฒนาโดย Twitter ตั้งแต่ปี 2012 เป็นระบบ tracing open-source รุ่นแรก ๆ ที่นำแนวคิดของ Google Dapper มาใช้จริงใน production เขียนด้วย Java มี ecosystem ที่โตและเสถียรมาก รองรับ instrumentation library ในหลายภาษา (Java, Python, Go, Ruby, Node.js) ผ่าน Brave และ OpenTelemetry

Zipkin มีจุดเด่นที่ setup ง่าย — single JAR สามารถรันได้ทันที ใช้ in-memory storage สำหรับ test หรือ Elasticsearch/MySQL/Cassandra สำหรับ production UI ของ Zipkin เรียบง่าย อาจไม่ฉูดฉาดเท่า Jaeger แต่ทำงานได้ครบฟังก์ชันหลัก และยังรองรับ dependency graph แบบ service-to-service

เปรียบเทียบ Jaeger vs Zipkin

หัวข้อJaegerZipkin
LanguageGoJava
OriginUber (CNCF graduated)Twitter (Apache)
StorageCassandra, Elasticsearch, Badger, KafkaMySQL, Elasticsearch, Cassandra, in-memory
Resource usageต่ำถึงปานกลางต่ำ (single JAR)
UIฟีเจอร์ครบ, visualization ดีเรียบ, เข้าใจง่าย
DeploymentKubernetes-first, OperatorJAR, Docker, Kubernetes
OpenTelemetryรองรับเต็มรูปแบบ (native)รองรับผ่าน exporter
Communityเติบโตเร็ว, CNCF backingเสถียร, older ecosystem

เลือกตัวไหนดี

หากกำลังสร้างระบบ cloud-native ใหม่บน Kubernetes และมีแผนจะใช้ OpenTelemetry อยู่แล้ว — Jaeger เป็นตัวเลือกที่เข้ากันดีที่สุด เพราะ protocol, storage, และ operator ถูกออกแบบให้ทำงานร่วมกันตั้งแต่ day-1 อีกทั้งยังได้ backing จาก CNCF ทำให้ทิศทางการพัฒนาสอดคล้องกับ ecosystem โดยรวม

ส่วน Zipkin เหมาะกับทีมที่ใช้ Java-heavy stack อยู่แล้ว ต้องการระบบที่ setup ได้เร็ว, resource น้อย, และ library stable ที่ผ่านการใช้งานจริงมาหลายปี — เช่น Spring Boot application ที่ใช้ Spring Cloud Sleuth (เวอร์ชันเก่าก่อน Micrometer Tracing) หรือระบบ legacy ที่ยังไม่พร้อมย้ายไป OTEL

Instrumentation — เริ่มยังไง

การนำ tracing ไปใช้ต้อง instrument code ที่ boundary ของแต่ละ service — จุดสำคัญที่ควร instrument: HTTP server/client, gRPC call, database query, message queue (publish/consume), cache operation ปัจจุบัน OpenTelemetry (OTEL) กลายเป็นมาตรฐาน vendor-neutral ที่รองรับทั้ง Jaeger และ Zipkin เพียงปรับ exporter ก็สลับ backend ได้

ตัวอย่างการ setup OpenTelemetry SDK ใน Python เพื่อส่ง trace ไป Jaeger:

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

provider = TracerProvider()
exporter = OTLPSpanExporter(endpoint="jaeger-collector:4317", insecure=True)
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)

tracer = trace.get_tracer("order-service")

with tracer.start_as_current_span("process_order") as span:
    span.set_attribute("order.id", order_id)
    span.set_attribute("user.id", user_id)
    # business logic here

Sampling — ข้อพิจารณาเรื่อง Cost

ระบบที่มี traffic สูงเก็บ trace ทุก request เป็นไปไม่ได้เพราะ storage จะโตเร็วมาก การตั้ง sampling rate เช่น 10% ของ request หรือใช้ tail-based sampling (เก็บเฉพาะ trace ที่มี error หรือ latency สูง) เป็นแนวทางที่ balance ระหว่างข้อมูลที่ได้กับต้นทุน storage

Jaeger รองรับ adaptive sampling ที่ปรับ rate ให้เหมาะกับแต่ละ endpoint อัตโนมัติ ส่วน Zipkin มักใช้ probabilistic sampler ขนาดคงที่ และสามารถเสริมด้วย OTEL Collector สำหรับ tail-based sampling ได้ทั้งสองตัว

สรุป

Distributed tracing เป็นเครื่องมือที่ขาดไม่ได้สำหรับ microservices ยุคใหม่ ช่วยให้ทีม dev และ ops มองเห็น flow ของ request ข้าม service ได้ชัดเจน Jaeger และ Zipkin ต่างก็เป็นตัวเลือก open-source ที่แข็งแรง เลือกได้ตาม stack และทิศทางของระบบ

ไม่ว่าเลือกตัวไหน แนะนำให้ใช้ OpenTelemetry เป็น layer instrumentation เพื่อให้สามารถเปลี่ยน backend ได้ในอนาคตโดยไม่ต้องแก้ code ของ application — และเริ่มจาก sampling rate ต่ำ ๆ ก่อน แล้วค่อยปรับเพิ่มเมื่อเข้าใจภาระของ backend