Data source là gốc của mọi thứ trong Grafana — không có nó thì panel chẳng vẽ được gì. Bài này đi sâu cách Grafana kết nối tới các nguồn, các loại data source phổ biến, và cách viết truy vấn cho ba "ngôn ngữ" quan trọng nhất: PromQL (Prometheus), SQL (MySQL/PostgreSQL) và LogQL (Loki), cùng những khái niệm query dùng chung như time range, $__interval và Explore mode.
Một data source là cấu hình kết nối tới một hệ thống chứa dữ liệu. Bạn khai báo nó một lần (trong Connections → Data sources hoặc qua provisioning), rồi mọi panel chỉ việc chọn data source đó và viết query. Mỗi loại data source có một query editor riêng phù hợp với ngôn ngữ truy vấn của nó.
Khi khai báo, ba thông tin quan trọng nhất là:
http://prometheus:9090 hay mysql-prod:3306. Đây là nơi Grafana gửi query tới.| Access mode | Cách hoạt động | Khi nào dùng |
|---|---|---|
| Server (proxy) | Trình duyệt gọi Grafana server, server đứng ra gọi data source rồi trả kết quả về. Đây là mặc định và khuyến nghị. | Gần như mọi trường hợp. Data source không cần lộ ra Internet, credential nằm an toàn ở server, tránh lỗi CORS. |
| Browser (direct) | Trình duyệt của người dùng gọi thẳng tới data source, bỏ qua Grafana server. | Rất hiếm — chỉ khi nguồn phải nằm cùng mạng với client và không đi qua được server. Dễ dính CORS và lộ endpoint. |
Danh sách các data source phổ biến và chúng lưu loại dữ liệu gì:
| Data source | Loại dữ liệu | Ngôn ngữ truy vấn |
|---|---|---|
| Prometheus | Metrics (time series) — thu thập theo kiểu pull, giám sát hạ tầng & app. | PromQL |
| Loki | Logs — log tập trung, gắn label giống Prometheus. | LogQL |
| MySQL | Dữ liệu quan hệ / nghiệp vụ trong bảng SQL. | SQL |
| PostgreSQL | Dữ liệu quan hệ / nghiệp vụ; hay kèm TimescaleDB cho time series. | SQL |
| Elasticsearch | Logs & document full-text; phân tích theo bucket thời gian. | Lucene / Query DSL |
| InfluxDB | Metrics time series (IoT, sensor, ứng dụng). | Flux / InfluxQL |
| CloudWatch | Metrics & logs của hạ tầng AWS (EC2, RDS, Lambda...). | Metric query / Logs Insights |
| Tempo | Traces phân tán — theo vết một request xuyên nhiều service. | TraceQL |
Prometheus lưu metrics dưới dạng chuỗi time series, mỗi chuỗi được định danh bởi tên metric + tập label, ví dụ http_requests_total{method="GET", handler="/api"}. PromQL là ngôn ngữ để lọc, tổng hợp và tính toán trên các chuỗi này.
Có hai kiểu truy vấn:
| Kiểu query | Trả về | Dùng cho |
|---|---|---|
| Instant query | Một giá trị duy nhất tại một thời điểm (mới nhất). | Panel Stat, Gauge, Table — chỉ cần con số hiện tại. |
| Range query | Chuỗi giá trị theo nhiều mốc thời gian trong time range. | Panel Time series (đồ thị đường) — vẽ diễn biến theo thời gian. |
Bốn loại metric cần phân biệt vì cách query khác nhau:
| Loại | Đặc điểm | Ví dụ |
|---|---|---|
| Counter | Chỉ tăng (reset về 0 khi restart). Không đọc trực tiếp — phải bọc rate(). | http_requests_total |
| Gauge | Lên xuống tự do, đọc trực tiếp là có nghĩa. | node_memory_Available_bytes |
| Histogram | Chia quan sát vào các bucket (_bucket, _sum, _count). Dùng để tính quantile phía server. | http_request_duration_seconds |
| Summary | Giống histogram nhưng quantile được tính sẵn tại client, không gộp được giữa nhiều instance. | rpc_duration_seconds |
Vì sao counter phải dùng rate()? Giá trị thô của counter (vd 1.240.512 request tích luỹ) gần như vô nghĩa và tụt về 0 mỗi lần service restart. Cái ta quan tâm là tốc độ tăng mỗi giây. Hàm rate() tính độ dốc trung bình trên một khoảng thời gian và tự xử lý các lần reset counter:
# request mỗi giây, trung bình trong 5 phút gần nhất
rate(http_requests_total[5m])
Các hàm PromQL then chốt:
| Hàm | Ý nghĩa |
|---|---|
rate(v[5m]) | Tốc độ tăng/giây trung bình của counter trên cửa sổ 5 phút. Mượt, phù hợp cho cảnh báo & đồ thị. |
irate(v[5m]) | Tốc độ tức thời, chỉ lấy 2 điểm cuối. Nhạy với đột biến, tốt để soi spike nhưng gai góc. |
sum by(label)(...) | Cộng gộp các chuỗi, giữ lại nhóm theo label chỉ định (bỏ các label còn lại). |
histogram_quantile(q, ...) | Tính phân vị (vd p95, p99) từ các bucket của histogram. |
Ví dụ thực tế — tổng request/s toàn hệ thống gom theo status code:
sum by(status_code) (rate(http_requests_total[5m]))
Ví dụ kinh điển — độ trễ p95 từ một histogram (chú ý phải sum ... by(le) trước khi tính quantile):
histogram_quantile( 0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le) )
Tỉ lệ lỗi (error rate) — phần trăm request trả về mã 5xx:
sum(rate(http_requests_total{status_code=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
[...] nên chứa ít nhất 4 lần scrape interval (thường là [5m] nếu scrape mỗi 15–30s). Cửa sổ quá nhỏ → đồ thị gãy khúc & nhiều lỗ; quá lớn → mượt nhưng chậm phản ứng với thay đổi.Với MySQL/PostgreSQL, bạn viết SQL bình thường nhưng để vẽ được time series, Grafana yêu cầu kết quả có một số hình dạng nhất định. Quan trọng nhất: phải có một cột thời gian (được đặt bí danh là time) cùng một hoặc nhiều cột giá trị số.
Grafana cung cấp các macro được thay thế lúc chạy theo time range & độ phân giải hiện tại của dashboard:
| Macro | Thay bằng | Công dụng |
|---|---|---|
$__timeFilter(col) | col BETWEEN '...' AND '...' | Lọc theo đúng time range đang xem — đặt trong mệnh đề WHERE. |
$__timeGroup(col, '1m') | Biểu thức gom nhóm theo bucket thời gian | Gộp các dòng vào từng khoảng (1m, 5m...) để vẽ time series mượt. |
$__interval | vd 30s, 1m | Bước thời gian Grafana tự tính từ độ rộng panel & time range; dùng làm bucket size. |
$__timeFrom() / $__timeTo() | Mốc đầu / cuối của range | Khi cần chèn trực tiếp biên thời gian. |
Ví dụ query cho panel Time series (PostgreSQL) — số đơn hàng theo từng khoảng thời gian:
SELECT $__timeGroup(created_at, $__interval) AS "time", count(*) AS orders FROM orders WHERE $__timeFilter(created_at) GROUP BY 1 ORDER BY 1;
Ví dụ query cho panel Table — không cần cột time, chỉ cần các cột muốn hiển thị dưới dạng bảng:
SELECT product_name AS "Sản phẩm", count(*) AS "Số đơn", sum(amount) AS "Doanh thu" FROM orders WHERE $__timeFilter(created_at) GROUP BY product_name ORDER BY "Doanh thu" DESC LIMIT 20;
$__timeFilter() nghĩa là query quét toàn bộ bảng bất kể time range — cực chậm và tạo tải nặng lên DB. Luôn để macro time filter trong WHERE cho mọi query đọc dữ liệu vận hành.Loki là hệ thống log của Grafana Labs, thiết kế theo tư duy Prometheus: nó không index toàn văn nội dung log, mà chỉ index label của log stream (như app, namespace, pod). Một truy vấn LogQL luôn bắt đầu bằng stream selector trong { }:
# chọn tất cả log của app "api"
{app="api"}
Sau selector, thêm các filter expression để lọc theo nội dung dòng log:
| Toán tử | Ý nghĩa |
|---|---|
|= "error" | Dòng có chứa chuỗi "error". |
!= "debug" | Dòng không chứa chuỗi "debug". |
|~ "5\\d\\d" | Khớp biểu thức chính quy (regex). |
!~ "..." | Không khớp regex. |
# log của api có chứa "error", loại bỏ dòng health-check
{app="api"} |= "error" != "healthz"
LogQL cũng làm được metric query — biến log thành số để vẽ đồ thị. Ví dụ đếm tốc độ dòng log/giây:
# số dòng log mỗi giây của app api, cửa sổ 5 phút
rate({app="api"}[5m])
# tốc độ dòng log lỗi, gom theo pod
sum by(pod) (rate({app="api"} |= "error" [5m]))
$app hoặc $namespace cho cả panel metrics lẫn panel logs, và tương quan chúng trên cùng một dashboard khi điều tra sự cố.Dù dùng nguồn nào, có một số khái niệm về truy vấn lặp lại ở khắp Grafana:
| Khái niệm | Ý nghĩa |
|---|---|
| Time range | Khoảng thời gian đang xem, chọn ở góc trên phải (vd "Last 6 hours"). Được truyền vào mọi query của dashboard. |
$__interval | Bước thời gian Grafana tự tính = time range ÷ số pixel ngang của panel. Dùng làm cửa sổ rate() động hoặc bucket size, tránh vẽ quá nhiều/quá ít điểm. |
$__rate_interval | Biến chuyên cho rate() của Prometheus: đảm bảo cửa sổ luôn ≥ 4× scrape interval, tránh đồ thị bị lỗ khi zoom sát. |
| refId (A/B/C) | Một panel có thể chứa nhiều query, mỗi query mang một refId. Cho phép vẽ nhiều chuỗi từ nhiều nguồn hoặc kết hợp qua transform/expression. |
| Time series frame | Dạng dữ liệu "cột time + cột giá trị số" — Grafana hiểu là đồ thị theo thời gian. |
| Table frame | Dạng bảng phẳng nhiều cột bất kỳ, không nhất thiết có trục thời gian — dùng cho panel Table. |
Nhiều query trên một panel: ví dụ panel latency có thể chứa ba query cùng lúc — refId A vẽ p50, refId B vẽ p95, refId C vẽ p99 — dùng chung một trục thời gian. Bạn cũng có thể để refId A lấy từ Prometheus và refId B lấy từ một nguồn khác rồi so sánh.
Time series frame vs table frame là phân biệt hay gây bối rối: cùng một query SQL, nếu bạn alias cột thời gian là time và group theo bucket → Grafana coi là time series và vẽ đường; nếu không có cột time → nó rơi về table frame. Chọn sai frame là lý do phổ biến khiến panel "không hiện gì" dù query chạy đúng.
Explore mode là chế độ truy vấn ad-hoc, tách khỏi dashboard: mở một khung query đơn, thử PromQL/LogQL/SQL, xem kết quả tức thì, rồi mới đưa vào panel. Đây là nơi lý tưởng để dò dữ liệu, gỡ query và nhảy qua lại giữa metrics ↔ logs khi điều tra sự cố.
$__rate_interval thay vì hardcode [5m] trong panel Prometheus, và dùng $__interval cho $__timeGroup trong SQL. Nhờ vậy đồ thị tự thích nghi khi bạn zoom in/out mà không phải sửa query.