Mục lục

Lesson 9.2: Distributed Tracing

Cách theo dấu hành trình của một yêu cầu (Tracing) đi qua hệ thống Microservices phức tạp.

Observability
Microservices
Tracing

Thời lượng: 25 phút
Level: Advanced
Yêu cầu: Đã hiểu về Logging và Trace ID.

Mục tiêu bài học

Sau bài học này, bạn sẽ:

  • Hiểu khái niệm Spans và Traces trong hệ thống phân tán.
  • Biết cách truyền (Propagate) Context giữa các service qua HTTP Headers.
  • Sử dụng các bộ công cụ như Jaeger hoặc Zipkin để trực quan hóa luồng đi của dữ liệu.

Nội dung chính

1. Tại sao cần Tracing?

Trong hệ thống Monolith, bạn chỉ cần đọc log 1 chỗ. Trong Microservices, một request "Mua hàng" có thể đi qua: Gateway -> Order Service -> Inventory -> Payment -> Shipping -> Email.

Nếu Email báo lỗi, làm sao bạn biết lỗi đó thuộc về request nào từ Gateway?

Distributed Tracing sinh ra để giải quyết việc này bằng cách gán một "Chứng minh thư" duy nhất cho toàn bộ hành trình đó.

2. Thuật ngữ quan trọng

  • Trace: Toàn bộ bản đồ hành trình của một request từ đầu đến cuối.
  • Span: Một đơn vị công việc (một bước nhỏ) trong hành trình. (VD: "Thời gian gọi Database", "Thời gian gọi sang Service B").
  • Root Span: Span đầu tiên tại cửa ngõ hệ thống (Gateway).

3. Context Propagation (Truyền ngữ cảnh)

Làm sao để Service B biết được Trace ID từ Service A gửi sang? Chúng ta sử dụng HTTP Headers.

Tiêu chuẩn phổ biến nhất hiện nay là W3C Trace Context: Header traceparent: 00-4bf92f35... sẽ được truyền đi xuyên suốt. Mọi thư viện Tracking (như OpenTelemetry) đều hỗ trợ việc tự động "tiêm" (inject) và "trích xuất" (extract) header này.


Nguyên tắc then chốt

"Đừng bao giờ bắt đầu một yêu cầu mới mà không có Trace ID."

Nếu không có Trace ID, bạn đang vận hành một hệ thống "mù". Trace ID phải được sinh ra ngay tại giây đầu tiên request chạm vào hệ thống và phải được trả về cho Client trong response header để hỗ trợ việc debug.


Thực hành

Bài tập 1: Đọc biểu đồ Jaeger

Bối cảnh: Bạn xem biểu đồ Tracing và thấy Service A mất 2 giây để phản hồi. Bên dưới Service A, có 2 Spans:

  • Span gọi DB: mất 100ms.
  • Span gọi Service B: mất 1.8s.

Câu hỏi:

  • Lỗi bottleneck (nghẽn) nằm ở đâu? Tại code của Service A hay tại Service B?
  • Bạn sẽ làm gì tiếp theo để tìm ra nguyên nhân?
Xem phân tích
  • Kết luận: Lỗi nằm ở Service B. Service A chỉ đang "đứng đợi" Service B trả lời.
  • Hành động: Bạn nhấn vào Span của Service B trên biểu đồ Tracing. Nó sẽ dẫn bạn đến các Spans con của Service B, từ đó bạn có thể thấy Service B đang bị chậm ở bước nào (VD: chậm ở Query DB hoặc chậm ở Logic xử lý).

Tình huống thực tế

Scenario 1: Debug lỗi "biến mất"

Bối cảnh: Người dùng báo lỗi: "Tôi đã thanh toán thành công nhưng chưa nhận được email".

Giải quyết:

  1. Bạn lấy request_id từ log của hệ thống Thanh toán.
  2. Dán mã này vào phần tìm kiếm của Jaeger.
  3. Jaeger hiển thị một bản đồ: Thanh toán xong (OK) -> Gọi sang Email Service -> Trả về lỗi 503 (Service Unavailable).
  4. Bạn phát hiện ra Email Service bị quá tải vào đúng thời điểm đó và không có cơ chế Retry. Nếu không có Tracing, bạn sẽ phải lục tung log của 2-3 service khác nhau để "mò kim đáy bể".

Câu hỏi phỏng vấn

Senior Level

  1. Q: "Sampling Rate" trong Tracing là gì? Tại sao không nên trace 100% request? A:
    • Sampling Rate: Tỷ lệ số lượng request được ghi lại (VD: 10% hoặc 1%).
    • Lý do: Tracing tốn tài nguyên CPU để xử lý và tốn rất nhiều dung lượng bộ nhớ. Với các hệ thống khổng lồ, việc trace 100% (hàng triệu lượt/giây) sẽ làm chậm chính hệ thống đó. Thông thường ta chỉ trace một tỷ lệ nhỏ, hoặc chỉ trace những request bị chậm/lỗi.

Tóm tắt

Những điều cần nhớ

  • Trace ID là sợi chỉ đỏ xuyên suốt hệ thống.
  • Span giúp đo lường thời gian xử lý của từng bước.
  • Sử dụng OpenTelemetry để làm tiêu chuẩn chung cho mọi ngôn ngữ (Java, Go, Node...).

Bước tiếp theo

Trong bài học cuối cùng: Lesson 9.3: Metrics & Alerting - Bạn sẽ học cách thiết kế các bảng Dashboard sức khỏe hệ thống và đặt cảnh báo tự động.

Tiếp tục bài 9.3 →

Quảng cáo
mdhorizontal