Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Bài 26 — Monitoring — Three Pillars (Metrics, Logs, Traces)

Đã đọc 0/14 mục · còn khoảng 11 phút
Cách chúng tôi ghi nhận

Một mục được tính là đã đọc khi nó nằm giữa màn hình đủ lâu so với độ dài của nó (bảng và sơ đồ tính một nửa), bạn vẫn đang cuộn hoặc bấm phím, và bạn đã thấy tới cuối mục. Lướt nhanh hoặc để tab mở không được tính. Chúng tôi chỉ lưu thời gian đọc từng mục — không lưu gì khác.

Mở đầu — vì sao bài này quan trọng

Hãy tưởng tượng bạn là DevOps engineer trực ca lúc 2 giờ sáng. Điện thoại rung liên tục: khách hàng báo trang thanh toán của một sàn thương mại điện tử ở TP.HCM đang "quay vòng vòng" không tải nổi. Sếp nhắn tin. CEO nhắn tin. Và bạn — người duy nhất đang thức — mở laptop ra và... không biết bắt đầu từ đâu. Server nào đang lỗi? Lỗi ở tầng ứng dụng hay database? Request nào bị treo? Nếu hệ thống của bạn chỉ có mỗi vài dòng log rời rạc, đêm đó sẽ rất dài.

Đây chính là lý do observability (khả năng quan sát) ra đời, và tại sao nó khác với monitoring (giám sát) truyền thống. Monitoring trả lời câu hỏi "hệ thống có đang chạy không?" dựa trên những thứ bạn đã biết trước để đo. Observability tiến xa hơn: nó giúp bạn trả lời cả những câu hỏi mà bạn chưa từng nghĩ tới khi sự cố xảy ra — mà không cần deploy lại code để thêm log.

Nền tảng của observability được xây trên ba trụ cột (Three Pillars): Metrics, Logs, và Traces. Đây là ba loại dữ liệu telemetry mà mọi hệ thống production hiện đại đều cần. Bài học này sẽ giúp bạn hiểu bản chất từng trụ cột, khi nào dùng cái nào, và cách chúng bổ trợ nhau để biến một đêm trực căng thẳng thành một cuộc điều tra có phương pháp. Đây là kiến thức nền tảng — trước khi bạn học sâu vào Prometheus, Grafana hay Jaeger ở các bài sau, bạn cần "khung tư duy" này trước.

Khái niệm cốt lõi

Để hiểu và vận hành một hệ thống production, bạn cần ba loại telemetry (dữ liệu đo lường từ xa) khác nhau. Mỗi loại trả lời một nhóm câu hỏi riêng.

Trụ cộtTrả lời câu hỏiĐặc điểm dữ liệuTool tiêu biểu
Metrics"Có gì đó sai không? Sai bao nhiêu?"Số liệu tổng hợp theo thời gianPrometheus, Datadog
Logs"Chính xác chuyện gì đã xảy ra?"Sự kiện chi tiết dạng textELK, Loki, Splunk
Traces"Chậm/lỗi ở đâu trong luồng request?"Hành trình một request qua nhiều serviceJaeger, Tempo, OpenTelemetry

Metrics — Con số kể chuyện

Metrics là các giá trị số được đo lường theo thời gian (time-series data). Ví dụ: CPU đang ở 85%, có 1.200 request mỗi giây, tỷ lệ lỗi (error rate) là 2,3%, độ trễ p99 là 800ms. Đặc điểm quan trọng nhất của metrics là chúng đã được tổng hợp (aggregated) — bạn không lưu từng request riêng lẻ mà lưu con số đại diện.

Ưu điểm: metrics cực kỳ nhẹ và rẻ để lưu trữ. Một chuỗi metric có thể lưu hàng tháng chỉ tốn vài MB. Chúng lý tưởng cho dashboard và alerting (cảnh báo) — bạn set ngưỡng "nếu error rate > 5% thì báo động". Nhược điểm: metrics cho bạn biết có vấn đề nhưng không cho biết tại sao. Con số 5% lỗi không nói cho bạn biết request nào lỗi hay lỗi vì lý do gì.

Người ta thường dùng bốn "golden signals" của Google SRE làm metrics cốt lõi: Latency (độ trễ), Traffic (lưu lượng), Errors (lỗi), và Saturation (mức bão hòa tài nguyên).

Logs — Nhật ký chi tiết

Logs là các bản ghi sự kiện rời rạc, mỗi dòng mô tả một chuyện đã xảy ra tại một thời điểm cụ thể: "10:32:05 — user 8842 đăng nhập thất bại — sai mật khẩu". Khác với metrics đã tổng hợp, logs giữ nguyên chi tiết. Đây là nơi bạn đọc để hiểu chính xác điều gì diễn ra.

Xu hướng hiện đại là structured logging (log có cấu trúc), thường ở định dạng JSON, thay vì text tự do. Thay vì viết "Order 123 failed", bạn viết {"level":"error","order_id":123,"user_id":8842,"reason":"payment_timeout"}. Log có cấu trúc cho phép máy tìm kiếm, lọc và phân tích dễ dàng — điều tối quan trọng khi bạn có hàng triệu dòng log mỗi ngày.

Nhược điểm của logs: chúng nặng và đắt. Một hệ thống lớn có thể sinh ra hàng terabyte log mỗi ngày, tốn kém để lưu trữ và index. Vì vậy quản lý log level (DEBUG, INFO, WARN, ERROR) và retention (thời gian giữ) là bài toán quan trọng.

Traces — Hành trình của một request

Trong kiến trúc microservices, một request từ người dùng có thể đi qua 5, 10, thậm chí 30 service khác nhau: API Gateway → Auth Service → Order Service → Payment Service → Inventory Service... Khi request đó chậm 3 giây, câu hỏi khó nhất là: chậm ở service nào?

Distributed tracing giải quyết đúng bài toán này. Mỗi request được gắn một trace ID duy nhất, và mỗi chặng đi qua một service tạo ra một span (một đoạn công việc có thời gian bắt đầu/kết thúc). Ghép tất cả span lại theo trace ID, bạn có một bức tranh dạng thác nước (waterfall) cho thấy request tiêu tốn thời gian ở đâu — ví dụ: Payment Service chiếm 2,8 giây trong tổng 3 giây, còn lại chỉ vài chục ms.

Traces là trụ cột "trẻ" nhất và khó triển khai nhất, vì nó đòi hỏi context propagation — truyền trace ID xuyên suốt qua mọi service. Đây là lúc OpenTelemetry trở thành chuẩn công nghiệp giúp việc này dễ hơn.

Ba trụ cột phối hợp thế nào

Điểm mấu chốt: không trụ cột nào đủ một mình. Metrics báo cho bạn có cháy (alert error rate tăng). Traces chỉ cho bạn đám cháy ở phòng nào (service Payment chậm). Logs cho bạn biết nguyên nhân cháy (kết nối tới cổng thanh toán VNPay bị timeout). Quy trình điều tra sự cố lý tưởng đi theo trình tự: Metrics → Traces → Logs, từ tổng quan đến chi tiết.

Tình huống thực tế

Ví dụ 1 — Sàn TMĐT bị nghẽn ngày sale 12/12

Một sàn thương mại điện tử tại Việt Nam (giả định tên "ShopViet") chạy chương trình sale lớn ngày 12/12. Khoảng 20 giờ, dashboard Grafana của đội DevOps hiện metric error rate của checkout service nhảy từ 0,5% lên 18%. Đây là tín hiệu từ trụ cột Metrics — họ biết có vấn đề, nhưng chưa biết tại sao.

Đội mở công cụ tracing (Jaeger) và lọc các trace bị lỗi trong khung 20h. Biểu đồ waterfall cho thấy các request checkout đều treo tại span gọi tới Inventory Service — service kiểm tra tồn kho — với thời gian lên tới 9 giây rồi timeout. Trụ cột Traces đã khoanh vùng thủ phạm.

Cuối cùng, họ lọc log của Inventory Service theo trace ID của một request lỗi cụ thể. Log có cấu trúc hiện rõ: {"level":"error","msg":"DB connection pool exhausted","pool_size":20,"waiting":340}. Trụ cột Logs cho câu trả lời cuối: connection pool tới database chỉ cấu hình 20 kết nối, nhưng lượng truy cập ngày sale khiến 340 request phải xếp hàng chờ. Đội tăng pool size lên 100 và thêm read replica, hệ thống hồi phục sau 8 phút.

Bài học: Ba trụ cột phối hợp theo trình tự metrics → traces → logs đã rút ngắn thời gian điều tra từ hàng giờ mò mẫm xuống chưa đầy 10 phút. Nếu chỉ có logs, đội đã phải grep qua hàng triệu dòng mà không biết bắt đầu từ service nào.

Ví dụ 2 — Fintech và cái bẫy chi phí logging

Một startup fintech ở Singapore ban đầu quyết định "log mọi thứ" ở level DEBUG cho toàn bộ hệ thống, gửi hết vào một cụm Elasticsearch. Trong ba tháng, hóa đơn lưu trữ log tăng vọt lên hơn 12.000 USD/tháng — cao hơn cả chi phí chạy chính ứng dụng. Tệ hơn, khi có sự cố thật, việc tìm log cần thiết giữa biển log DEBUG lại chậm chạp.

Họ tái cấu trúc: chuyển phần lớn tín hiệu "sức khỏe hệ thống" sang metrics (rẻ hơn ~100 lần để lưu), chỉ giữ log ở level INFO trở lên cho production, và áp dụng sampling cho traces (chỉ lưu 10% trace thành công nhưng 100% trace lỗi). Chi phí giảm còn khoảng 3.000 USD/tháng mà khả năng debug lại tốt hơn.

Bài học: Chọn đúng trụ cột cho đúng loại tín hiệu là quyết định về chi phí, không chỉ kỹ thuật. Đừng dùng logs làm metrics.

Ví dụ 3 — Ngân hàng số với request "biến mất"

Một ngân hàng số ở Đông Nam Á gặp khiếu nại: một số khách chuyển tiền báo "giao dịch treo", tiền bị trừ nhưng bên nhận chưa nhận được. Metrics tổng thể hoàn toàn xanh — error rate 0%, latency bình thường. Vấn đề là các giao dịch này quá hiếm (vài ca mỗi ngày trên hàng trăm nghìn) nên bị "nuốt" trong con số trung bình.

Nhờ đã gắn trace ID vào mọi giao dịch, đội support lấy mã giao dịch từ khách, tra ngược trace ID tương ứng, và thấy request đã đi qua Payment Service thành công nhưng span gửi message sang Notification Service không bao giờ hoàn tất — do một message bị kẹt trong hàng đợi Kafka. Log của consumer xác nhận lỗi deserialize một định dạng message cũ.

Bài học: Với những lỗi hiếm mà metrics tổng hợp che giấu, traces (kết hợp trace ID có thể tra cứu) là cứu cánh. Đây là lý do observability mạnh hơn monitoring truyền thống: nó trả lời được câu hỏi bạn không lường trước.

Hướng dẫn từng bước

Đây là lộ trình thực tế để đưa Three Pillars vào một hệ thống của bạn:

  • Bắt đầu bằng Metrics (dễ nhất, ROI cao nhất). Cài đặt thu thập bốn golden signals cho mỗi service: latency, traffic, errors, saturation. Với hệ sinh thái phổ biến, bạn expose một endpoint /metrics để Prometheus scrape. Dựng dashboard tối thiểu và một vài alert quan trọng nhất.
  • Chuẩn hóa Logs sang structured logging. Chuyển toàn bộ log sang JSON có cấu trúc với các trường thống nhất: timestamp, level, service, trace_id, message. Định nghĩa rõ log level cho từng môi trường (production thường INFO trở lên). Đẩy log về một nơi tập trung (Loki hoặc ELK).
  • Thêm trace_id vào mọi log và mọi request. Đây là bước "keo dán" ba trụ cột lại. Khi mỗi dòng log mang trace_id, bạn có thể nhảy từ một trace lỗi sang đúng những dòng log liên quan chỉ bằng một cú click. Đây gọi là correlation (tương quan) — sức mạnh thật sự của observability.
  • Triển khai Distributed Tracing với OpenTelemetry. Dùng OpenTelemetry SDK/auto-instrumentation để tự động sinh span và truyền context giữa các service. Bắt đầu với sampling khiêm tốn (ví dụ 10%) để kiểm soát chi phí, nhưng luôn lấy 100% với request lỗi.
  • Thiết lập quy trình điều tra chuẩn. Đào tạo đội theo trình tự Metrics → Traces → Logs: nhìn dashboard để phát hiện, dùng trace để khoanh vùng service, đọc log để tìm nguyên nhân gốc.

Lỗi thường gặp & mẹo

  • Nhầm monitoring với observability. Cài Prometheus rồi tưởng đã "có observability" là sai. Bạn cần cả ba trụ cột và khả năng correlate chúng qua trace_id, không chỉ vài dashboard.
  • Dùng logs để làm việc của metrics. Đếm số lần một sự kiện xảy ra bằng cách grep log là chậm và đắt. Nếu bạn cần đếm/đo theo thời gian, hãy tạo metric.
  • Cardinality nổ (high cardinality). Đừng gắn nhãn metric bằng các giá trị vô hạn như user_id hay request_id. Mỗi tổ hợp nhãn tạo một chuỗi thời gian mới — hàng triệu user_id sẽ làm sập Prometheus. Cardinality cao thuộc về logs và traces, không phải metrics.
  • Log không có trace_id. Đây là lỗi phổ biến nhất khiến ba trụ cột trở nên rời rạc. Không có trace_id, bạn không thể nhảy từ trace sang log — mất đi giá trị lớn nhất.
  • Không sampling traces. Lưu 100% mọi trace ở hệ thống lớn sẽ cực kỳ tốn kém. Mẹo: dùng tail-based sampling — luôn giữ trace lỗi và trace chậm, chỉ lấy mẫu phần "bình thường".
  • Log level bừa bãi. Log DEBUG chạy trên production làm nhiễu và đội chi phí. Định nghĩa rõ ý nghĩa từng level và tôn trọng nó.
  • Mẹo quan trọng: hãy dùng OpenTelemetry làm chuẩn thống nhất ngay từ đầu. Nó là chuẩn mở (vendor-neutral), giúp bạn không bị khóa vào một nhà cung cấp và có thể đổi backend (Jaeger, Tempo, Datadog...) mà không viết lại code instrumentation.

Bài tập thực hành

  • Phân loại tín hiệu. Với mỗi câu hỏi sau, xác định nên trả lời bằng trụ cột nào (Metrics/Logs/Traces): (a) "API của chúng ta có đang chậm hơn hôm qua không?" (b) "Tại sao đơn hàng #55213 lại thất bại?" (c) "Trong luồng đặt vé, bước nào tốn nhiều thời gian nhất?" (d) "Đã có bao nhiêu lần đăng nhập thất bại trong giờ qua?"
  • Thiết kế trên giấy. Chọn một ứng dụng bạn biết (ví dụ app đặt đồ ăn). Liệt kê: 4 golden-signal metrics quan trọng nhất, 3 trường bắt buộc cho structured log, và mô tả một trace điển hình đi qua ít nhất 3 service.
  • Mô phỏng điều tra. Viết lại kịch bản Ví dụ 1 (ShopViet) bằng lời của bạn, nêu rõ ở mỗi bước bạn nhìn vào trụ cột nào và câu hỏi nào được trả lời. Mục tiêu là ghi nhớ trình tự Metrics → Traces → Logs.
  • Bài toán chi phí. Giả sử hệ thống bạn sinh 500GB log/ngày ở level DEBUG. Đề xuất ít nhất ba biện pháp cụ thể để giảm chi phí observability mà không làm mất khả năng debug sự cố.

Tóm tắt

Observability được xây trên ba trụ cột, mỗi trụ cột trả lời một nhóm câu hỏi khác nhau về hệ thống production:

  • Metrics — số liệu tổng hợp theo thời gian, nhẹ và rẻ, trả lời "có vấn đề không, mức độ nào". Lý tưởng cho dashboard và alert.
  • Logs — bản ghi sự kiện chi tiết, trả lời "chính xác chuyện gì đã xảy ra". Nên dùng structured logging (JSON).
  • Traces — hành trình một request qua nhiều service, trả lời "chậm/lỗi ở đâu trong luồng". Thiết yếu cho microservices.
Không trụ cột nào đủ một mình. Sức mạnh thật sự đến từ việc correlate chúng — đặc biệt qua trace_id xuyên suốt — theo trình tự điều tra Metrics → Traces → Logs: phát hiện, khoanh vùng, rồi tìm nguyên nhân gốc. Ghi nhớ ba nguyên tắc thực hành: chọn đúng trụ cột cho đúng tín hiệu (kiểm soát chi phí), luôn gắn trace_id vào log, và dùng OpenTelemetry làm chuẩn thống nhất. Đây là nền tảng tư duy để bạn bước vào các bài chuyên sâu tiếp theo về Prometheus, Grafana và distributed tracing.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi