Tracing phân tán và log theo request

Chủ đề Bài đọc thử miễn phí

Bài toán

Khi một request đi qua hàng chục service, metric của từng service cho biết có chậm, log của từng service cho biết từng mảnh; không cái nào trả lời "request này chậm vì đâu" hay "trang này tốn bao nhiêu". Tracing phân tán ghép các mảnh của cùng một request thành một cây span nhờ trace context truyền theo mọi lời gọi. Theo Salesforce 2019, metric là thông tin về mọi sự kiện qua một điểm, còn trace là về một sự kiện qua nhiều điểm (Salesforce 2019).

Ba bài toán con xuất hiện ở mọi nguồn:

  • Truyền context: mọi tầng phải chuyển tiếp trace ID, nên tracing chỉ phủ được nhanh ở chỗ có framework dùng chung (Pinterest 2017), và khó ở chỗ giao tiếp không có lớp metadata (message passing của Elixir, Discord 2026).
  • Lấy mẫu: ghi span tốn CPU và lưu trace tốn tiền, nên chỉ trace 0,3–1% request; nhưng lấy mẫu theo request không hợp với fan-out lớn.
  • Kho lưu và truy vấn: ngay cả ở 1% mẫu, hệ lớn sinh hàng trăm TB span mỗi ngày (ClickHouse 2026).

Một hướng rẻ hơn, bổ sung cho tracing: gom thông tin chính của request vào một dòng log có cấu trúc mỗi request mỗi service (Stripe 2019) hoặc lưu sự kiện rộng đủ chiều (ClickHouse 2025). Hạ tầng metric/log chung, giám sát hệ giám sát nằm ở Observability và monitoring.

Diễn tiến theo thời gian

  • 2015 · LinkedIn: trace của các service trong cùng request gốc được Samza gom và phát lên Kafka; inCapacity dựng call graph realtime, gắn pagekey (trang khởi phát) vào trace. Self-latency (latency trừ thời gian chờ phía sau) cho phép đi từ triệu chứng xuống tầng thủ phạm tự động; tính được chi phí mỗi trang và capacity theo dự báo lượt xem. LinkedIn 2015
  • 2017 · Pinterest: hàng trăm microservice, home feed gọi mạng hàng trăm lần. Instrumentation là phần lớn công sức: tracer riêng cho monolith Python (một lần deploy), cấu hình toàn cục trong service framework Java (hàng trăm app phải deploy lại). Lấy mẫu 0,3% vì ghi span tốn CPU hai chữ số phần trăm; collector Spark Streaming kiểm chất lượng span, lấy mẫu thêm lúc ingest, lưu Elasticsearch. Pinterest 2017
  • 2018 · Netflix: interceptor HTTP/gRPC đẩy trace qua Kafka; theo Netflix call graph chỉ có ích cơ bản, nên cho ứng dụng gắn định danh nghiệp vụ (playback session) để gom nhiều trace thành một phiên, kèm analyzer trả lời câu hỏi hay gặp (vì sao không được 4K). Netflix 2018
  • 2018 · LinkedIn (Aeon): với luồng một chiều không có request/response để trace, latency đầu-cuối tính bằng stream-stream join giữa tracking event bắt đầu và kết thúc có chung khoá, cache có TTL vài phút. LinkedIn 2018
  • 2019 · Salesforce: trace theo request qua chuỗi service và theo bản ghi qua các pha ETL; cái giá là mọi team trong chuỗi phải chuyển tiếp trace ID, một chi phí phối hợp của microservice. Salesforce 2019
  • 2019 · Stripe: canonical log line: cuối mỗi request phát một dòng gom user, rate limit, thời gian DB, số query...; viết trong ensure để luôn có, lỗi của nó không làm hỏng request. Schema chốt bằng protobuf, gửi bất đồng bộ vào Kafka → S3 → Redshift/Presto, nuôi cả Developer Dashboard cho khách. Stripe 2019
  • 2019 · Tokio (dự án mã nguồn mở): trong runtime async một thread chạy xen nhiều task nên thứ tự log không còn chỉ ra ngữ cảnh; thư viện tracing mang ngữ cảnh bằng span (khoảng thời gian, lồng thành cây) và field có kiểu, tách API instrumentation khỏi Subscriber (bộ thu), đổi bộ lọc lúc chạy. Cùng ý tưởng distributed tracing nhưng bên trong một process Tokio 2019
  • 2025 · ClickHouse: bỏ tiền tổng hợp thành metric, lưu wide event đủ chiều và tổng hợp lúc truy vấn để trả lời "spike này là insert nào"; theo ClickHouse (nhà cung cấp kho dữ liệu). ClickHouse 2025
  • 2025 · Anthropic: agent không tất định giữa các lần chạy nên lỗi kiểu "không tìm thấy thông tin hiển nhiên" không tái hiện được; thêm tracing production đầy đủ theo dõi mẫu quyết định và tương tác của agent (không xem nội dung hội thoại). Anthropic 2025
  • 2026 · Discord: Elixir không có header cho message, nên bọc message trong Envelope mang trace context; phía nhận chấp nhận cả message cũ lẫn mới để triển khai không downtime. Fan-out tới 1 triệu session làm nổ số span: lấy mẫu lớp hai theo số người nhận (1 người 100%, từ 10.000 người 0,1%). Overhead lớn nhất là giải context của 99% request không lấy mẫu: chỉ gửi context khi có lấy mẫu, đọc byte cờ trước khi giải, cấm session tạo root span sau fan-out (CPU 55% → 45%). Discord 2026
  • 2026 · LinkedIn (qua ClickHouse): tracing OpenTelemetry ở 1% mẫu vẫn khoảng 0,8 nghìn tỉ span, 200 TB/ngày; 3 DC × 22 shard ClickHouse, ghi hai cụm đọc một (red-black), ingest dưới 10 giây, lấy trace theo ID dưới 750 ms. Kinh nghiệm vận hành từ dự án tracing làm việc gom metadata của 13 tỉ metric vào cùng công nghệ rẻ hơn hẳn. ClickHouse 2026
  • 2026 · Uber: tìm phụ thuộc fail-close của mọi API mà không dùng trace: lấy mẫu 0,01% với availability 99,9% thì cần khoảng 2 ngày 8 giờ mới có 10 mẫu lỗi của một phụ thuộc; tail sampling quá tốn. Thay bằng middleware yarpc gắn ID request vào context, nối mỗi lời gọi ra với request vào và đếm mọi lỗi bằng metric; cạnh có xác suất caller lỗi khi callee lỗi ≥ 0,8 là fail-close, ≤ 0,2 là fail-open. Uber 2026

Các lựa chọn và đánh đổi

Lựa chọn Được Mất Nguồn
Head sampling (quyết định ở span gốc) Rẻ, trace đầy đủ khi đã chọn Bỏ lỡ request hiếm/chậm; với fan-out thì số span tỉ lệ số người nhận Pinterest 2017, Discord 2026
Lấy mẫu thêm lúc ingest Chỉ giữ trace giá trị cao, sửa span lỗi Thêm một tầng xử lý stream Pinterest 2017
Lấy mẫu theo kích thước fan-out Giữ được hình dạng fan-out mà không nổ span Phải truyền thêm metadata (số người nhận) Discord 2026
Chỉ gửi context khi được lấy mẫu Bỏ chi phí giải context của 99% request Tầng giữa có thể tự mở trace mới, ra trace không đủ Discord 2026
Canonical log line / wide event Không cần truyền context, query đơn giản, rẻ để lưu lâu Không thấy quan hệ cha-con giữa service Stripe 2019, ClickHouse 2025
Gắn ngữ cảnh người khởi phát (pagekey) Tính chi phí và capacity theo sản phẩm Phải truyền thêm một trường qua mọi tầng LinkedIn 2015

Quy tắc rút ra

  1. Tracing phủ nhanh ở nơi có framework chung: đặt instrumentation và cấu hình bật/tắt trong framework của mỗi ngôn ngữ, không trong từng service (Pinterest 2017).
  2. Đổi định dạng message để mang context thì phía nhận phải hiểu cả cũ lẫn mới trước khi phía gửi đổi; khi deploy, node cũ và mới luôn cùng chạy (Discord 2026).
  3. Lấy mẫu theo hình dạng tải: request/response thì head sampling; fan-out thì giảm mẫu theo số người nhận (Discord 2026).
  4. Đo overhead của tracing bằng công cụ khác (stacktrace định kỳ, profiler): tracer không thấy chi phí của chính nó, và phần đắt thường là việc vô ích cho request không lấy mẫu (Discord 2026).
  5. Trước khi có tracing, một dòng log tổng hợp mỗi request mỗi service đã trả lời được phần lớn câu hỏi lúc sự cố; chốt schema của nó nếu dữ liệu dùng cho analytics (Stripe 2019).
  6. Gắn ID của điểm khởi phát (trang, tính năng) vào trace để biến dữ liệu hiệu năng thành chi phí và capacity theo sản phẩm (LinkedIn 2015).
  7. Telemetry không được làm hỏng request, nhưng lỗi của nó phải báo ngay (Stripe 2019).
  8. Với sự kiện hiếm (lỗi), trace lấy mẫu quá thưa; đếm toàn bộ bằng metric có ngữ cảnh request ở middleware cho câu trả lời trong vài phút thay vì vài ngày. Uber 2026

Câu hỏi mở

  • Tail sampling (quyết định sau khi request xong, giữ request chậm/lỗi) chưa có nguồn production nào trong wiki; các nguồn đều head sampling cộng lọc thêm. Uber 2026 nói rõ vì sao không làm: theo họ không dễ và hạ tầng quá tốn, nên đếm mọi lỗi bằng metric có ngữ cảnh ở middleware thay cho trace (Uber 2026).
  • Chưa có nguồn nào đưa tỉ lệ chi phí của tracing so với hạ tầng sản phẩm; Pinterest 2017 chỉ nói overhead CPU hai chữ số khi ghi span, LinkedIn 2026 nói khối lượng dữ liệu.
  • Canonical log line/wide event (Stripe, ClickHouse) và tracing (Pinterest, Discord, LinkedIn) là hai hướng; chưa có nguồn so sánh trực tiếp khả năng chẩn đoán của hai cách trên cùng hệ.
  • Liên hệ: Observability và monitoring (hạ tầng metric/log, gauge, chi phí quan sát), Realtime và fan-out (fan-out làm nổ số span), Monolith và microservices — đi và quay lại (chi phí phối hợp trace ID), Xử lý sự cố và on-call (trace dùng lúc điều tra), Chi phí hạ tầng và build vs buy (chi phí theo trang).