DevOps 7 — Giám sát & Observability

13 thg 7, 2026 5 lượt xem
#observability
#monitoring
#devops
#grafana
#prometheus

Mở đầu: vì sao cần "nhìn thấy" hệ thống

Khi bạn chỉ có một ứng dụng nguyên khối (monolith) chạy trên một máy chủ, việc tìm lỗi khá đơn giản: SSH vào máy, đọc một file log, xem top là gần như đủ. Nhưng hệ thống hiện đại thường gồm hàng chục đến hàng trăm dịch vụ nhỏ (microservices), chạy trên nhiều container, nhiều node, co giãn động theo tải. Một request của người dùng có thể đi qua API gateway → service xác thực → service đơn hàng → service thanh toán → cơ sở dữ liệu → hàng đợi message. Khi nó chậm hoặc lỗi, "chậm ở đâu" trở thành câu hỏi khó.

Đây chính là lý do observability (khả năng quan sát) ra đời. Bài này sẽ đi sâu từ khái niệm nền tảng đến công cụ và thực hành cụ thể: ba trụ cột logs–metrics–traces, Prometheus/Grafana, alerting, và bộ chỉ số SLI/SLO/SLA cùng error budget.

Monitoring khác Observability như thế nào

Hai từ này hay bị dùng lẫn lộn, nhưng khác nhau về tư duy.

Monitoring là việc theo dõi những thứ bạn đã biết trước là quan trọng: CPU, RAM, số lỗi HTTP 500, độ trễ trung bình. Bạn định nghĩa sẵn các câu hỏi và dựng dashboard/alert để trả lời chúng. Monitoring trả lời câu hỏi: "Hệ thống có đang khỏe theo các tiêu chí tôi đặt ra không?"

Observability là khả năng suy luận về trạng thái bên trong của hệ thống chỉ qua các tín hiệu nó phát ra (output), kể cả với những câu hỏi bạn chưa từng nghĩ tới lúc thiết kế. Nó trả lời câu hỏi: "Tại sao đúng nhóm người dùng ở khu vực X, dùng phiên bản app Y, vào khung giờ Z lại gặp lỗi?" — một câu hỏi mà bạn không thể dựng sẵn dashboard cho mọi tổ hợp.

Nói ngắn gọn: monitoring là tập con của observability. Monitoring báo cho bạn biết có gì đó sai; observability giúp bạn điều tra để hiểu vì sao sai mà không cần deploy lại code để thêm log.

Ba trụ cột của Observability

Observability được xây trên ba loại dữ liệu (telemetry) bổ trợ cho nhau. Không trụ cột nào tự nó đủ.

Trụ cộtBản chất dữ liệuTrả lời câu hỏiCông cụ phổ biếnĐặc tính chi phí
LogsBản ghi sự kiện rời rạc, có dấu thời gian"Chính xác chuyện gì đã xảy ra ở thời điểm đó?"ELK (Elasticsearch + Logstash + Kibana), LokiKhối lượng lớn, tốn lưu trữ
MetricsSố liệu đo dạng chuỗi thời gian (time-series)"Xu hướng/định lượng thế nào theo thời gian?"Prometheus, Thanos, VictoriaMetricsRẻ, nén tốt, query nhanh
TracesHành trình một request qua nhiều dịch vụ"Request đi qua đâu, chậm ở khâu nào?"OpenTelemetry, Jaeger, Tempo, ZipkinThường lấy mẫu (sampling)

Logs — nhật ký sự kiện

Log là dòng văn bản ghi lại một sự kiện cụ thể. Vấn đề lớn nhất trong hệ phân tán là log nằm rải rác trên hàng trăm container, mà container thì sinh ra và biến mất liên tục. Hai nguyên tắc cốt lõi:

1. Log có cấu trúc (structured logging). Thay vì in chuỗi tự do, hãy in JSON để máy có thể truy vấn theo trường:

{"ts":"2026-06-30T10:15:02Z","level":"error","service":"payment",
 "trace_id":"a1b2c3","user_id":"u-991","msg":"charge failed",
 "amount":250000,"gateway":"vnpay","err":"timeout"}

trace_id trong log là chìa khóa để nối log với trace (xem phần dưới).

2. Tập trung hóa (centralized logging). Agent (Filebeat, Fluent Bit, Promtail...) thu log từ mọi node và đẩy về một nơi. Hai lựa chọn phổ biến:

  • ELK Stack: Elasticsearch lưu và đánh chỉ mục toàn văn (full-text), Kibana để xem. Mạnh khi cần tìm kiếm tự do, nhưng tốn tài nguyên.
  • Grafana Loki: chỉ đánh chỉ mục theo nhãn (label) chứ không index toàn văn, nên rẻ hơn nhiều. Triết lý của Loki là "giống Prometheus nhưng cho log".

Metrics — số liệu chuỗi thời gian

Metric là một con số đo được tại một thời điểm, gắn nhãn, ví dụ http_requests_total{service="order",status="500"}. Vì chỉ là số, metric nén rất tốt và truy vấn cực nhanh, lý tưởng cho dashboard và alert.

Prometheus là chuẩn de-facto trong thế giới cloud-native. Điểm đặc trưng là pull model: thay vì ứng dụng tự đẩy số liệu đi, Prometheus chủ động cào (scrape) endpoint /metrics của từng dịch vụ theo chu kỳ. Lợi ích: Prometheus biết chính xác target nào đang sống (nếu scrape thất bại thì target "down"), và phía ứng dụng không cần biết server giám sát ở đâu.

Cấu hình scrape tối thiểu:

# prometheus.yml
global:
  scrape_interval: 15s
scrape_configs:
  - job_name: 'order-service'
    static_configs:
      - targets: ['order-service:8080']

Có bốn loại metric cơ bản: Counter (chỉ tăng, ví dụ tổng số request), Gauge (lên xuống tự do, ví dụ số kết nối hiện tại), Histogram (phân phối giá trị theo các "rổ", ví dụ phân bố độ trễ), và Summary (tương tự histogram nhưng tính quantile phía client).

Giới thiệu PromQL. Ngôn ngữ truy vấn của Prometheus rất mạnh. Vài ví dụ thực dụng:

# Tỷ lệ request lỗi 5xx trong 5 phút qua
sum(rate(http_requests_total{status=~"5.."}[5m]))
  / sum(rate(http_requests_total[5m]))

# Độ trễ phân vị 95 (p95) tính từ histogram
histogram_quantile(0.95,
  sum(rate(http_request_duration_seconds_bucket[5m])) by (le))

Hàm rate() tính tốc độ tăng trung bình mỗi giây của một counter trong cửa sổ thời gian — đây là hàm bạn sẽ dùng nhiều nhất.

Traces — dấu vết phân tán

Trace theo dõi một request xuyên suốt nhiều dịch vụ. Mỗi chặng công việc là một span; các span nối với nhau qua một trace_id chung tạo thành cây thể hiện toàn bộ hành trình. Nhờ trace bạn nhìn thấy: request mất 800ms, trong đó 600ms nằm ở một truy vấn DB chậm — điều mà metric tổng hợp không chỉ ra được.

OpenTelemetry (OTel) là chuẩn mở (vendor-neutral) để sinh và thu telemetry, gồm SDK cho ứng dụng và Collector để nhận/xử lý/chuyển tiếp dữ liệu. Backend hiển thị trace phổ biến là Jaeger hoặc Grafana Tempo.

Để trace hoạt động xuyên dịch vụ, mỗi service phải truyền bối cảnh (context propagation) — thường qua header traceparent (chuẩn W3C Trace Context) — cho dịch vụ kế tiếp. Vì lưu mọi trace rất tốn kém, người ta dùng sampling: chỉ giữ lại một tỷ lệ (ví dụ 1–10%), nhưng thường ưu tiên giữ trọn các trace bị lỗi hoặc chậm bất thường.

Sơ đồ luồng thu thập telemetry

Dưới đây là cách dữ liệu chảy từ các dịch vụ về các backend giám sát và lên màn hình vận hành.

Lưu ý sự khác biệt về mũi tên: metric được Prometheus kéo về (pull), còn log và trace được đẩy đi (push) tới agent/collector. Grafana đứng ở tầng trên cùng, đọc cả ba nguồn để cho phép kỹ sư nhảy qua lại giữa metric → log → trace của cùng một sự cố.

Bốn tín hiệu vàng và phương pháp RED/USE

Đo cái gì cho đúng? Đừng đo tất cả mọi thứ — hãy đo cái thật sự phản ánh trải nghiệm người dùng. Google SRE đề xuất bốn tín hiệu vàng (four golden signals):

  • Latency (độ trễ): thời gian xử lý một request. Quan trọng: tách riêng độ trễ của request thành côngthất bại, vì lỗi nhanh có thể che lấp thành công chậm.
  • Traffic (lưu lượng): mức nhu cầu lên hệ thống, ví dụ số request/giây.
  • Errors (lỗi): tỷ lệ request thất bại (lỗi rõ ràng như 5xx, hoặc sai về mặt nghiệp vụ).
  • Saturation (mức bão hòa): hệ thống "đầy" đến đâu — CPU, bộ nhớ, hàng đợi. Đây là chỉ báo sớm cho thấy sắp quá tải.

Có hai khung tư duy bổ sung phổ biến:

  • Phương pháp RED (cho dịch vụ, hướng request): Rate (số request/s), Errors (số lỗi/s), Duration (phân phối độ trễ). Rất hợp với microservices.
  • Phương pháp USE (cho tài nguyên, hướng phần cứng): Utilization (mức sử dụng), Saturation (mức bão hòa/chờ), Errors (lỗi thiết bị). Hợp để soi CPU, đĩa, mạng.

Một mẹo: RED nhìn từ phía người dùng gọi vào, USE nhìn từ phía tài nguyên bên trong. Kết hợp cả hai cho bức tranh đầy đủ.

Dashboard với Grafana

Grafana là công cụ trực quan hóa hàng đầu, có thể cắm vào nhiều nguồn (Prometheus, Loki, Tempo, Elasticsearch...). Vài nguyên tắc làm dashboard tốt:

  • Mỗi dashboard phục vụ một mục đích. Một dashboard tổng quan cho lãnh đạo (SLO, traffic), một dashboard chi tiết cho on-call (per-service RED), một cho hạ tầng (USE).
  • Đặt số quan trọng nhất ở trên cùng, bên trái — nơi mắt nhìn vào trước.
  • Dùng biến (template variables) để chọn service/environment thay vì sao chép dashboard.
  • Liên kết chéo (correlation): cấu hình để từ một điểm tăng vọt trên đồ thị metric có thể click thẳng sang log/trace tương ứng cùng khoảng thời gian. Đây là sức mạnh thực sự của observability.

Hãy cảnh giác với "wall of graphs" — màn hình 50 biểu đồ trông oách nhưng không ai đọc nổi khi sự cố xảy ra. Ít mà đúng thì hơn.

Alerting — cảnh báo đúng lúc, đúng việc

Dashboard chỉ hữu ích khi có người nhìn. Alert mới là thứ chủ động đánh thức bạn dậy. Trong hệ Prometheus, luật cảnh báo được định nghĩa rồi gửi tới Alertmanager để gom nhóm, chặn lặp (deduplicate), tạm tắt (silence) và định tuyến tới Slack/Email/PagerDuty.

# alert rule
groups:
  - name: availability
    rules:
      - alert: HighErrorRate
        expr: |
          sum(rate(http_requests_total{status=~"5.."}[5m]))
            / sum(rate(http_requests_total[5m])) > 0.05
        for: 10m
        labels: { severity: critical }
        annotations:
          summary: "Tỷ lệ lỗi 5xx vượt 5% trong 10 phút"

Lưu ý mệnh đề for: 10m: điều kiện phải đúng liên tục 10 phút mới bắn alert, tránh báo động giả do nhiễu nhất thời.

Tránh alert fatigue (mệt mỏi vì cảnh báo). Đây là tử huyệt của nhiều đội. Nếu mỗi đêm bị đánh thức 20 lần bởi cảnh báo vô nghĩa, kỹ sư sẽ học cách phớt lờ — và rồi bỏ lỡ cái cảnh báo thật. Nguyên tắc:

  • Mọi alert phải hành động được (actionable). Nếu nhận alert mà chẳng phải làm gì, hãy xóa nó.
  • Cảnh báo theo triệu chứng, không theo nguyên nhân. Báo "người dùng đang gặp lỗi" (triệu chứng), đừng báo "CPU node-7 cao" (nguyên nhân, có thể vô hại).
  • Phân tầng mức độ: critical (đánh thức người ngay) vs warning (xem vào giờ hành chính).
  • Gắn runbook (hướng dẫn xử lý) vào mỗi alert để người trực biết làm gì.

SLI, SLO, SLA và Error Budget

Đây là bộ khái niệm nền tảng của SRE, giúp chuyển "độ tin cậy" từ cảm tính sang định lượng.

  • SLI (Service Level Indicator): một chỉ số đo thực tế về chất lượng. Ví dụ: "tỷ lệ request thành công trong tháng" = 99,95%. SLI là sự thật được đo.
  • SLO (Service Level Objective): mục tiêu nội bộ cho SLI. Ví dụ: "tỷ lệ thành công ≥ 99,9% mỗi tháng". SLO là cam kết đội tự đặt ra.
  • SLA (Service Level Agreement): cam kết với khách hàng kèm hậu quả (thường là tài chính). Ví dụ: "nếu uptime < 99,5%, hoàn 10% phí". SLA luôn lỏng hơn SLO để có vùng đệm.

Quan hệ thực hành: SLI ≤ đo lường thực → so với SLO (mục tiêu) → SLA (hợp đồng) lỏng hơn SLO.

Error budget (ngân sách lỗi) là khái niệm tinh tế và quan trọng nhất. Nếu SLO là 99,9% thành công, thì 0,1% còn lại chính là "ngân sách" cho phép hỏng. Với một tháng (~43.200 phút), 0,1% tương đương khoảng 43 phút được phép downtime/lỗi.

Error budget biến mâu thuẫn kinh điển giữa Dev (muốn release nhanh) và Ops (muốn ổn định) thành một con số chung:

  • Còn ngân sách → cứ mạnh dạn deploy tính năng mới, chấp nhận rủi ro.
  • Cạn ngân sách → đóng băng tính năng, dồn lực vào ổn định cho tới khi hồi phục.

Nó cũng chống lại cám dỗ "đuổi theo 100%": độ tin cậy tuyệt đối là cực kỳ đắt đỏ và thường không cần thiết — người dùng không phân biệt nổi 99,99% với 100%, trong khi chi phí thì khác biệt khổng lồ.

Health check và uptime

Lớp cơ bản nhất của giám sát là health check — một endpoint cho biết dịch vụ còn sống và sẵn sàng phục vụ không. Trong Kubernetes, có hai loại probe quan trọng (chủ đề được đào sâu ở bài về container/orchestration):

  • Liveness probe: "Tiến trình có còn sống không?" Nếu fail, Kubernetes khởi động lại container.
  • Readiness probe: "Đã sẵn sàng nhận traffic chưa?" Nếu fail, Kubernetes ngừng gửi traffic nhưng không restart — hữu ích lúc khởi động hoặc khi DB tạm mất.
# Kubernetes pod
livenessProbe:
  httpGet: { path: /healthz, port: 8080 }
  initialDelaySeconds: 10
  periodSeconds: 10
readinessProbe:
  httpGet: { path: /ready, port: 8080 }
  periodSeconds: 5

Một thiết kế tốt: /healthz chỉ kiểm tra tiến trình nội bộ, còn /ready kiểm tra cả các phụ thuộc thiết yếu (DB, cache). Uptime là tỷ lệ thời gian dịch vụ ở trạng thái khỏe; các công cụ blackbox (Prometheus Blackbox Exporter, hoặc dịch vụ ngoài như UptimeRobot) thăm dò định kỳ từ bên ngoài để xác nhận góc nhìn của người dùng thực, bổ sung cho giám sát nội bộ.

Tóm tắt

Observability là khả năng hiểu trạng thái bên trong hệ thống qua tín hiệu nó phát ra, vượt xa monitoring vốn chỉ theo dõi những thứ đã biết trước. Nó dựa trên ba trụ cột: logs (sự kiện chi tiết, nên có cấu trúc và tập trung qua ELK/Loki), metrics (chuỗi thời gian, Prometheus với pull model và PromQL), và traces (hành trình request phân tán, OpenTelemetry + Jaeger/Tempo). Hãy ưu tiên đo bốn tín hiệu vàng (latency, traffic, errors, saturation) cùng khung RED cho dịch vụ và USE cho tài nguyên. Grafana hợp nhất ba nguồn này thành dashboard có khả năng liên kết chéo, còn Alertmanager lo cảnh báo — với kỷ luật "actionable, theo triệu chứng" để tránh alert fatigue. Cuối cùng, bộ SLI/SLO/SLA + error budget biến độ tin cậy thành con số có thể quản trị, cân bằng tốc độ phát triển và sự ổn định. Health/readiness probe và đo uptime là lớp nền đảm bảo dịch vụ luôn ở trạng thái phục vụ được.

Use case thực tế

Bối cảnh (minh hoạ): Đội vận hành cổng thanh toán của NCB nhận phản ánh rời rạc rằng "chuyển khoản đôi lúc bị chậm" vào giờ cao điểm 11h–13h, nhưng dashboard tổng quan vẫn xanh vì độ trễ trung bình chỉ 180ms. Đây đúng là điểm mù mà observability sinh ra để giải quyết.

Cách xử lý theo đúng bài:

  1. Đổi từ trung bình sang phân vị. Đội dựng lại panel Grafana dùng histogram_quantile(0.95, ...) trên http_request_duration_seconds_bucket của service chuyển khoản. p95 lộ ra 2,1 giây (số minh hoạ) trong khung 11h–13h — trong khi trung bình bị các request nhanh kéo xuống che lấp.
  2. Bốn tín hiệu vàng. Latency tăng nhưng Traffic và Errors bình thường; Saturation của pool kết nối DB chạm ~95% — chỉ báo bão hoà, không phải lỗi logic.
  3. Metric → trace. Từ điểm tăng vọt trên đồ thị, kỹ sư click chéo sang trace (OpenTelemetry + Tempo) của một request chậm: 1,7s trong tổng 2,1s nằm ở span truy vấn bảng lịch sử giao dịch — thiếu index cho khoảng thời gian bị quét nhiều nhất.
  4. Trace → log. Dùng trace_id nhảy thẳng sang log có cấu trúc để xác nhận truy vấn và tham số.

Kết quả (ước lượng): Sau khi thêm index và tăng pool kết nối, p95 giờ cao điểm về ~320ms. Đội bổ sung alert for: 10m trên p95 > 1s (theo triệu chứng người dùng, không theo CPU) và đặt SLO 99,9% cho tỷ lệ giao dịch dưới 1s — biến sự cố mơ hồ thành chỉ số quản trị được.

Ghi nhớ

  • Monitoring là tập con của observability: monitoring báo có gì đó sai theo tiêu chí đặt trước; observability giúp điều tra vì sao sai mà không phải deploy lại để thêm log.
  • Ba trụ cột bổ trợ nhau: logs (sự kiện chi tiết — nên có cấu trúc JSON và tập trung qua ELK/Loki), metrics (chuỗi thời gian rẻ, nhanh — Prometheus + PromQL), traces (hành trình request phân tán — OpenTelemetry + Jaeger/Tempo). trace_id là sợi chỉ nối cả ba.
  • Prometheus dùng pull model: chủ động scrape /metrics, nhờ đó phát hiện ngay target "chết"; rate()histogram_quantile() là hai công cụ PromQL dùng nhiều nhất.
  • Đo cái phản ánh người dùng: bốn tín hiệu vàng (latency, traffic, errors, saturation); RED cho dịch vụ (hướng request), USE cho tài nguyên (hướng phần cứng).
  • Alert phải actionable và theo triệu chứng, không theo nguyên nhân; dùng for: để chống báo giả, phân tầng critical/warning, gắn runbook — để tránh alert fatigue.
  • SLI (đo thực) ≤ SLO (mục tiêu nội bộ) ≤ nới lỏng thành SLA (cam kết khách hàng); error budget biến độ tin cậy thành con số: còn ngân sách thì mạnh dạn release, cạn thì đóng băng để ổn định.
  • Health check là lớp nền: liveness (fail → restart) khác readiness (fail → ngừng gửi traffic, không restart); đo uptime từ bên ngoài bằng blackbox để phản ánh góc nhìn người dùng thực.

Tự kiểm tra

  1. Phân biệt monitoring và observability bằng ví dụ một câu hỏi mà monitoring trả lời được nhưng observability mới giải quyết trọn vẹn.
  2. Vì sao Prometheus dùng pull model lại có lợi cho việc phát hiện target "chết"? Khác gì so với cách log và trace được thu thập?
  3. Bốn tín hiệu vàng là gì? RED và USE khác nhau ở góc nhìn nào, và mỗi khung hợp với loại đối tượng nào?
  4. Nếu SLO là 99,9% trong một tháng, error budget xấp xỉ bao nhiêu phút, và đội nên hành xử ra sao khi ngân sách gần cạn?
  5. Kể ba kỹ thuật cụ thể để tránh alert fatigue.
  6. trace_id trong log có cấu trúc giúp ích gì cho việc liên kết giữa ba trụ cột khi điều tra sự cố?

Nguồn tham khảo

  • Prometheus Documentation — mô hình pull, kiểu metric, PromQL, cấu hình scrape và Alertmanager.
  • Grafana Documentation — dashboard, template variables, kết nối nhiều data source (Prometheus/Loki/Tempo).
  • OpenTelemetry Documentation — SDK, Collector, context propagation và telemetry chuẩn vendor-neutral.
  • W3C Trace Context Recommendation — chuẩn header traceparent để truyền bối cảnh trace xuyên dịch vụ.
  • Google — Site Reliability Engineering (Beyer, Jones, Petoff, Murphy; O'Reilly), chương "Monitoring Distributed Systems" (bốn tín hiệu vàng) và "Service Level Objectives" (SLI/SLO/SLA, error budget). Đọc trực tuyến tại https://sre.google/books/
  • Grafana Loki Documentation — mô hình đánh chỉ mục theo nhãn cho log.

Đọc tiếp

DevOps 8 — Bảo mật & SRE

Bài viết liên quan

Hiểu container từ gốc: khác gì máy ảo, cơ chế Linux namespaces & cgroups, image gồm các lớp (layers) & chuẩn OCI, kiến trúc Docker (client/daemon/registry), và vòng đời một container.

13 thg 7, 2026 5

Chạy nhiều container cùng nhau: Docker Compose định nghĩa stack đa dịch vụ, mạng container (bridge, DNS nội bộ theo tên service), volume để lưu dữ liệu bền, và registry để chia sẻ image.

13 thg 7, 2026 5

Phân biệt Continuous Integration, Delivery và Deployment; giải phẫu một pipeline (trigger, stage, job, step, artifact) và các lớp kiểm thử xếp theo chi phí. Bài viết một workflow GitHub Actions hoàn chỉnh (build, test, Docker), so sánh với GitLab CI, quản lý secrets an toàn và chọn chiến lược release rolling/blue-green/canary kèm cách rollback.

13 thg 7, 2026 5

Dữ liệu bền và cấu hình trên Kubernetes: Volume, PersistentVolume & PersistentVolumeClaim, StorageClass & cấp phát động, lưu trữ cho StatefulSet, cùng ConfigMap và Secret để tách cấu hình khỏi image.

13 thg 7, 2026 5

Cảm nhận của bạn

Bình luận

Bạn cần để viết bình luận.

Chưa có bình luận. Hãy là người đầu tiên chia sẻ!