---
id: monitoring-prometheus
title: "Prometheus"
shortTitle: "Prometheus"
track: monitoring
trackTitle: "Monitoring & Alerting"
order: 1
level: core
status: published
estimatedMinutes: 40
prerequisites:
  - serverless-edge
next: monitoring-grafana
reviewedAgainst: 2026-10-12
sources:
  - title: "Prometheus — metric types"
    url: https://prometheus.io/docs/concepts/metric_types/
  - title: "Prometheus — querying basics"
    url: https://prometheus.io/docs/prometheus/latest/querying/basics/
---

# Prometheus

Bài này chạy Prometheus trong Docker và cho nó scrape chính nó. Bạn chưa cần app của mình export metric, vì Prometheus tự có sẵn metric để tập query.

## Để làm gì

Sau bài này, bạn đọc được một metric, phân biệt được counter với gauge, và viết được query `rate` cho loại số chỉ tăng. Grafana và alert ở các bài sau đều dựa trên những query này. Nếu hiểu sai loại metric, biểu đồ sẽ sai và alert cũng sai theo.

## Gồm những gì

- Prometheus chủ động kéo metric (scrape). Mặc định app không đẩy số tới Prometheus.
- Ba loại metric: counter, gauge, histogram.
- `rate()` trên counter.

Zabbix, Datadog, New Relic và Checkmk là những hệ monitoring khác, có bài riêng ở cuối track này. Azure Monitor là nơi xem metric của resource Azure: cùng mục đích với Prometheus nhưng cách thu thập và lưu trữ khác. Azure Monitor là bài thứ ba của track.

## Dùng khi nào

Bạn cần số liệu theo thời gian: request mỗi giây, RAM đang dùng, hàng đợi còn bao nhiêu job. Khi có sự cố "app chậm" mà không có metric, bạn chỉ còn log để đoán. Log kể chuyện của từng request, còn metric cho bạn thấy bức tranh của cả service.

Metric không thay được log. Metric cho biết mỗi phút có bao nhiêu order lỗi, nhưng không cho biết một order cụ thể lỗi vì sao.

## Kiến thức cốt lõi

Prometheus gọi HTTP tới target, thường là path `/metrics`, theo chu kỳ `scrape_interval`. Response ở dạng text, mỗi dòng gồm tên metric và một con số.

Counter chỉ tăng, hoặc về 0 khi process restart. Bạn dùng counter để đếm request hay đếm lỗi. Nếu vẽ thẳng giá trị counter lên biểu đồ, bạn chỉ thấy một đường đi lên mãi và không đọc được gì. `rate(http_requests_total[5m])` cho bạn tốc độ tăng trung bình mỗi giây trong 5 phút gần nhất. Docs querying cũng ghi rõ `rate` dành cho counter.

Gauge thì lên xuống tự do: RAM, số goroutine, số job trong queue. Bạn đọc gauge trực tiếp. Áp `rate` lên gauge không ra ý nghĩa gì, vì "mỗi giây đang dùng thêm bao nhiêu byte RAM" không phải câu hỏi bạn cần.

Histogram đếm số lần quan sát rơi vào từng bucket. Latency nên đo bằng histogram rồi tính quantile từ đó. Đừng dùng một gauge kiểu "latency của request cuối cùng" để làm SLO, vì một request chậm sẽ bị request ngay sau ghi đè và biến mất khỏi số liệu.

Trong hệ sinh thái Prometheus, tên counter thường kết thúc bằng `_total`. Đây không phải luật của ngôn ngữ query mà là convention được nêu trong docs metric types.

## Lệnh và code mẫu

Tạo file `prometheus.yml` trong `$HOME/devops-lab/monitoring`:

```yaml
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: prometheus
    static_configs:
      - targets: ["localhost:9090"]
```

```bash
mkdir -p "$HOME/devops-lab/monitoring"
cd "$HOME/devops-lab/monitoring"
docker run -d --name lab-prom -p 9090:9090 \
  -v "$PWD/prometheus.yml:/etc/prometheus/prometheus.yml:ro" \
  prom/prometheus:v2.55.0
```

Mở `http://127.0.0.1:9090` rồi gõ vào ô query:

```text
prometheus_http_requests_total
rate(prometheus_http_requests_total[1m])
```

Lúc mới chạy, Prometheus có thể cần một lát mới có điểm dữ liệu đầu tiên. Query `up` phải trả về 1:

```text
up
```

## Thực hành

1. Chạy container rồi query `up`. Giá trị 1 nghĩa là Prometheus đã scrape được chính nó.
2. Query `prometheus_http_requests_total`. Bấm Execute vài lần, bạn sẽ thấy số tăng dần.
3. Query `rate(...[1m])`. Số trả về nhỏ vì đơn vị là request mỗi giây, không phải tổng từ lúc process khởi động.
4. Xóa container bằng `docker rm -f lab-prom`. Dữ liệu metric của lab mất theo, vì container không gắn volume. Production phải có disk riêng hoặc remote storage, phần này bài không đề cập.

## Kết quả mong đợi

- `up == 1`.
- Counter tăng mỗi khi bạn tải lại trang query.
- `rate` không tăng mãi theo thời gian sống của process.

## Checklist

- [ ] Hiểu rằng scrape là Prometheus tự đi lấy số, mặc định app không đẩy.
- [ ] Với counter, dùng `rate` hoặc `increase`; không vẽ giá trị thô để làm SLO.
- [ ] Với gauge, đọc giá trị trực tiếp.
- [ ] Đo latency bằng histogram, không bằng một con số "request cuối cùng".
- [ ] Hiểu `up == 0` chỉ có nghĩa là không scrape được; bạn chưa biết bên trong app đang ra sao.

## Lỗi thường gặp

**Đặt alert khi counter vượt một ngưỡng.** Counter cứ tăng mãi, nên sau một tuần alert sẽ kêu liên tục dù hệ thống đang ổn. Hãy đặt alert trên `rate`.

**Dùng `rate` với cửa sổ ngắn hơn scrape interval.** Cửa sổ quá ngắn thì có quá ít điểm dữ liệu, query trả về rỗng hoặc nhảy lung tung. Cửa sổ nên dài gấp vài lần `scrape_interval`. Lab này scrape mỗi 15 giây, nên `[1m]` là mức tối thiểu tạm chấp nhận.

**Tin vào gauge latency trung bình do app tự tính.** Giá trị trung bình che mất các request chậm. Có histogram thì bạn mới nhìn được phần đuôi, ví dụ p99.

## Nguồn

1. [Metric types](https://prometheus.io/docs/concepts/metric_types/) — Prometheus, counter, gauge, histogram.
2. [Querying basics](https://prometheus.io/docs/prometheus/latest/querying/basics/) — `rate`.

## Tiếp theo

[Grafana và alert](./02-grafana.md)
