Observability thực chiến cho backend: metrics, logs, traces đo thật

Sê-ri nâng cao về khả năng quan sát hệ thống cho lập trình viên backend: Prometheus metrics, PromQL, percentile, RED/USE, cardinality, distributed tracing, structured logging, alerting — mỗi bài demo THẬT trên Prometheus + Go app + Jaeger trong Docker, đọc số liệu thật.

12/12 phần đã đăng Lập trình
1 Ba trụ cột observability: metrics, logs, traces — nhìn một request qua ba lăng kính Metrics, logs, traces không phải ba cách làm cùng một việc — chúng trả lời ba câu hỏi khác nhau. Bài này đo thật trên Prometheus + Go app: cùng một endpoint, metric cho 90 thành công/11 lỗi (có vấn đề không?), log JSON cho chi tiết từng request (chuyện gì xảy ra?), và trace_id nối các bước lại (lỗi ở đâu?). Khi nào dùng cái nào và vì sao cần cả ba. 22/09/2026 · 6 phút đọc 2 Bốn loại metric Prometheus: counter, gauge, histogram, summary — và khi nào dùng cái nào Counter, gauge, histogram, summary nghe na ná nhau nhưng trả lời bốn câu hỏi khác hẳn. Bài này instrument một Go app với cả bốn, bắn 150 request thật rồi đọc thẳng output /metrics: counter dừng ở 150, gauge vọt lên 51 lúc tải rồi về 0, histogram chia bucket cộng dồn, summary tự tính quantile phía client. Kèm bẫy chọn sai loại khiến số liệu thành vô dụng. 22/09/2026 · 7 phút đọc 3 PromQL cho ra hồn: rate, increase và sum by — biến counter thô thành câu trả lời Counter của Prometheus chỉ là con số cộng dồn vô nghĩa khi đọc trực tiếp — http_requests_total=1055 chẳng nói lên gì. Sức mạnh nằm ở PromQL. Bài này dựng một app với counter gắn nhãn path/status, bắn tải đều rồi chạy query thật trên obs-prom: rate() ra đúng 10/5/2 req/s, increase ra đúng 600 trong 1 phút, sum by gộp theo nhãn, và một dòng tính tỉ lệ lỗi 4.4%. 22/09/2026 · 6 phút đọc 4 p50, p95, p99: vì sao trung bình độ trễ nói dối và percentile mới nói thật Dashboard báo độ trễ trung bình 36ms — service khoẻ? Bài này chạy thật một app có phân bố lệch (95% nhanh, 5% chậm) rồi đo bằng histogram_quantile: trung bình 36ms và p95 25ms đều đẹp, nhưng p99 là 778ms — cứ 100 user thì 1 người chờ gần 0.8 giây. Và một bất ngờ: p99 đo được cao hơn cả giá trị chậm nhất thật, vì bucket chọn quá rộng. 22/09/2026 · 7 phút đọc 5 RED method: ba tín hiệu đủ để biết service có khoẻ không — và vì sao phải tách theo route Service của bạn khoẻ không? RED method trả lời bằng đúng ba tín hiệu: Rate, Errors, Duration. Bài này dựng thật một dashboard RED từ một Go service hai route, rồi cho thấy cú lừa chí mạng: tỉ lệ lỗi tổng hợp 3.9% trông chấp nhận được, nhưng tách theo route lộ ra /checkout đang lỗi 9.3% — đúng route tiền bạc. Chỉ hai metric, ba câu PromQL. 22/09/2026 · 7 phút đọc 6 USE method: vì sao utilization 100% chưa phải vấn đề, mà saturation mới là CPU 100% — hoảng không? Chưa chắc. USE method (Utilization, Saturation, Errors) cho tài nguyên chỉ ra rằng utilization cao một mình là tín hiệu mơ hồ. Bài này dựng thật một worker pool bị nạp quá sức: utilization chạm 100% nhưng không nói lên mức độ quá tải; chính saturation (hàng đợi đầy 20/20) và errors (41 job/s bị rớt) mới định lượng được service đang chết ngạt thế nào. 22/09/2026 · 7 phút đọc 7 Cardinality: vì sao một nhãn user_id vô hại có thể hạ gục cả Prometheus Thêm nhãn user_id vào một metric nghe tiện — lọc theo user mà. Nhưng bài này đo thật cái giá: cùng một app, metric gắn nhãn route tạo 3 chuỗi thời gian, metric gắn nhãn user_id tạo 10000; chỉ một metric sai làm tổng số chuỗi của Prometheus nhảy từ 729 lên 10732 (~14 lần). Và đó mới 10000 user — nhân thêm status, endpoint là nổ tổ hợp đủ làm Prometheus OOM mà chết. 22/09/2026 · 7 phút đọc 8 Distributed tracing: khi metric chỉ nói 'chậm', trace chỉ đúng span nào ngốn thời gian Metric báo checkout p99 = 127ms. Nhưng 127ms đó tiêu ở đâu — validate, query DB, hay gọi payment? Metric không biết. Bài này dựng thật tracing với OpenTelemetry và Jaeger: tạo span lồng nhau, export, rồi query Jaeger API lấy trace thật — và thấy ngay queryDB ngốn 91ms (72% tổng) trong khi validate chỉ 3.85ms. Đây là thứ metric tổng hợp không bao giờ chỉ ra được. 22/09/2026 · 7 phút đọc 9 Structured logging: vì sao log JSON đánh bại log văn bản, và trace_id nối log với trace Log văn bản thuần đọc bằng mắt thì được, nhưng máy khó truy vấn — grep với regex mong manh. Bài này chạy thật slog của Go in log JSON có cấu trúc, rồi dùng jq lọc theo level, theo độ trễ, tổng hợp doanh thu ngay trên log. Và cú chốt: gắn trace_id thật từ OpenTelemetry vào mỗi dòng log — thấy lỗi trong log là nhảy thẳng tới đúng trace trong Jaeger, khớp đã kiểm chứng. 22/09/2026 · 7 phút đọc 10 Alerting: vì sao 'for' trong alert rule là ranh giới giữa báo đúng và báo loạn Metric đẹp vô dụng nếu không ai nhìn lúc 3h sáng — đó là việc của alert. Nhưng alert sai cách còn tệ hơn không có: báo động giả làm kỹ sư tê liệt (alert fatigue). Bài này dựng thật alert rule trên Prometheus, cho hai alert cùng điều kiện chạy song song: cái không 'for' firing ngay tức khắc, cái có 'for: 30s' chờ pending 30 giây rồi mới firing — đo thật từng mốc chuyển trạng thái qua API. 22/09/2026 · 7 phút đọc 11 Chi phí observability: vì sao giám sát có thể tốn hơn hệ thống nó giám sát Dung lượng metric là tích của bốn thừa số — số chuỗi, tần suất lấy mẫu, bytes mỗi sample, và retention — mỗi thừa số là một đòn bẩy cắt chi phí. Bài này đo thật trên Prometheus: 78 samples/s ở scrape 5s, head chứa hơn 10.000 chuỗi (phần lớn là stale vẫn tốn RAM), rồi ngoại suy ra quy mô thật: một nhãn cardinality sai biến 7GB thành 730GB. Ba núm vặn để tiết kiệm mà không mù thông tin. 22/09/2026 · 6 phút đọc 12 Tổng kết Observability: ghép metric, trace, log thành một bức tranh — và checklist thực chiến Mười một phần qua ta dựng từng mảnh observability bằng demo đo thật. Bài cuối ghép chúng lại: một request duy nhất phát cả ba tín hiệu — metric, trace, log — chia sẻ cùng một trace_id, và chính trace_id đó là sợi chỉ nối metric báo động với log và trace để điều tra. Kèm bảng tổng hợp mọi con số đo thật xuyên suốt loạt bài và một checklist gắn observability vào service của bạn. 22/09/2026 · 7 phút đọc