Diagnostics with Tracing

Bài tóm tắt Tokio 2019 2. Tăng trưởng Độ khó: Trung bình

Tokio · 2019 · 2. Tăng trưởng · Độ khó: Trung bình — bài gốc

Bài giới thiệu thư viện của dự án mã nguồn mở Tokio (async runtime cho Rust), không phải hệ của một công ty. Wiki giữ phần lý do: log tuần tự hỏng khi chương trình bất đồng bộ.

Bối cảnh

  • Trong code đồng bộ, thứ tự log ngầm cho biết ngữ cảnh: các dòng giữa "accepted connection" và "closing connection" thuộc về kết nối đó. Trong hệ async như Tokio, một thread chạy xen kẽ nhiều task, nhiều worker thread chạy song song, nên thứ tự log không còn nói lên nhân quả: dòng "invalid request headers" không còn biết thuộc client nào. Log truyền thống chỉ ghi ngữ cảnh tĩnh (file, module, hàm), còn cái cần là ngữ cảnh động lúc chạy.

Thay đổi chính

  • Thư viện tracing (ban đầu tên tokio-trace, đổi tên vì không bắt buộc dùng runtime Tokio):
    • Span: một khoảng thời gian có bắt đầu và kết thúc; task vào span khi bắt đầu làm một việc và ra khi dừng, span lồng nhau thành cây; khi task nhường CPU rồi quay lại, ngữ cảnh đi theo span chứ không theo thread.
    • Event: điểm thời gian, tương đương dòng log, nhưng nằm trong cây span.
    • Field có kiểu gắn vào span/event (địa chỉ client, path, method), nên mỗi dòng mang theo ngữ cảnh của mọi span cha và máy đọc được: đếm request theo path, hay chỉ ghi toàn bộ vòng đời request khi nó kết thúc bằng lỗi.
  • Subscriber là điểm mở rộng thu và xử lý dữ liệu trace (in console, sau này metric, profiling, gửi sang OpenTelemetry/Jaeger); tracing-core là lõi nhỏ ổn định nối instrumentation với subscriber. Macro info!/debug!... tương thích với crate log để chuyển dần, cùng lớp tương thích tracing-log.
  • Ví dụ trong bài: service dưới tải với admin endpoint đổi bộ lọc lúc chạy để bật instrumentation chi tiết khi cần; với log thường không truy được lỗi 500 từ đâu, với span thì truy được.
  • Đã được Linkerd 2 dùng (2019).

Vì sao

  • Chương trình async làm mất mối liên hệ "thời điểm ghi log = ngữ cảnh"; ngữ cảnh phải được mang tường minh theo đơn vị công việc. Đây là cùng ý tưởng của distributed tracing, áp vào bên trong một process.

Bài học cho SWE

  • Khi một thread phục vụ nhiều request xen kẽ, log không kèm ID ngữ cảnh gần như vô dụng dưới tải; cần span hoặc ít nhất field ngữ cảnh trên mọi dòng.
  • Tách API instrumentation (thư viện dùng) khỏi bộ thu (ứng dụng chọn) cho phép thư viện gắn instrumentation mà không áp đặt backend.
  • Bật/tắt mức chi tiết lúc chạy giảm chi phí instrumentation lúc bình thường.

Liên quan