Giám sát Hệ thống Toàn diện với Prometheus v3 và Grafana 11 trên Production (Chuẩn SRE 2026)

Mục Lục Nội Dung

1. Tại sao Hệ thống Giám sát Truyền thống Thất bại Khi Vận hành Hạ tầng Cloud-Native Quy mô Lớn?

Trong kiến trúc hạ tầng hiện đại năm 2026—nơi các dịch vụ được đóng gói bằng container, tự động co giãn (Auto-scaling) trên kiến trúc Microservices với Docker và Kubernetes thực chiến và thay đổi địa chỉ IP liên tục theo vòng đời Pod—các công cụ giám sát thế hệ cũ dựa trên kiểm tra trạng thái tĩnh theo máy chủ (Host-based Nagios/Zabbix checks) hoặc chỉ cảnh báo theo ngưỡng phần trăm CPU đơn thuần bộc lộ ba điểm mù nghiêm trọng:

  1. Bùng nổ Số lượng Chuỗi Thời gian (High-Cardinality Time-Series Explosion): Khi lập trình viên vô tình gắn các nhãn (Labels) có tập giá trị không giới hạn như user_id, request_id, ip_address hoặc đường dẫn URL thô chưa chuẩn hóa vào metric, cơ sở dữ liệu chuỗi thời gian (TSDB) phải cấp phát hàng triệu chuỗi chỉ mục (Inverted Index postings) mới trong bộ nhớ RAM. Hậu quả là tiến trình giám sát tự sập vì cạn kiệt bộ nhớ trước cả khi kịp gửi cảnh báo cho đội ngũ vận hành.
  2. Bão Cảnh báo và Mệt mỏi Trực chiến (Alert Fatigue): Thiết lập cảnh báo kiểu CPU > 80% trong 2 phút hoặc HTTP 5xx > 5 requests tạo ra hàng trăm thông báo giả (False Positives) vào ban đêm dù người dùng cuối không hề bị ảnh hưởng, hoặc ngược lại, bỏ lỡ các sự cố suy giảm ngầm (Slow-burn degradation) làm tiêu hao toàn bộ ngân sách lỗi (Error Budget) của tháng.
  3. Phân mảnh Giữa Pull Scraping và OpenTelemetry (OTLP): Trước thế hệ Prometheus v3.x, việc kết hợp mô hình thu thập kéo (Pull /metrics) cho hạ tầng nhân Linux với chuẩn đẩy OpenTelemetry Protocol (OTLP) từ các ứng dụng Go/Python/Java đòi hỏi nhiều tầng chuyển đổi trung gian phức tạp, làm mất ngữ cảnh liên kết giữa Metrics, Logs và Distributed Traces (thông qua Exemplars).

Bài viết chuyên sâu này hướng dẫn đội ngũ Kỹ sư DevOps, SRE và Quản trị viên Hệ thống thiết kế, tính toán dung lượng và triển khai trọn vẹn nền tảng Observability chuẩn Production 2026 với Prometheus v3.x (tích hợp Native OTLP Receiver, Native Histograms, UTF-8 support), Node Exporter v1.8+, Alertmanager v0.27+ và Grafana 11.x (Provisioning-as-Code).


2. Kiến trúc Lưu trữ TSDB của Prometheus v3.x và Cơ chế Hợp nhất Pull Scrape + Native OTLP

Để vận hành ổn định trên các cụm máy chủ vật lý như triển khai cụm Kubernetes High Availability trên hạ tầng Bare Metal, kỹ sư SRE cần nắm vững luồng dữ liệu nội bộ bên trong công cụ lưu trữ TSDB (Time-Series Database) của Prometheus v3.x.

flowchart TD
    subgraph Sources["Tầng Phát Sinh Tín Hiệu (Telemetry Sources 2026)"]
        NE["Node Exporter v1.8+<br/>(Linux Kernel 6.12 / cgroups v2 / PSI)"]
        CAD["cAdvisor / Kubelet<br/>(Container Resource Metrics)"]
        APP["Microservices (Go / Python / Java)<br/>OpenTelemetry SDK (OTLP HTTP/Protobuf)"]
    end

    subgraph PromV3["Prometheus v3.x Server (TSDB Engine)"]
        SCRAPE["Pull Scrape Engine<br/>(Service Discovery + Relabeling)"]
        OTLP["Native OTLP Receiver<br/>(POST /api/v1/otlp/v1/metrics)"]
        WAL["Write-Ahead Log (WAL)<br/>& In-Memory Head Block (2h)"]
        COMPACT["Block Compactor<br/>(Immutable 2h Blocks + XOR Chunk Compression)"]
        RULE["Rule & PromQL Engine<br/>(Recording Rules & SLO Burn-Rate Alerts)"]
    end

    subgraph Downstream["Tầng Cảnh Báo, Trực Quan Hóa & Lưu Trữ Dài Hạn"]
        AM["Alertmanager v0.27+ Cluster<br/>(Grouping, Inhibition, Silencing)"]
        GRAF["Grafana 11.x<br/>(Provisioned Dashboards + Exemplars)"]
        OBJ["Long-Term Object Storage<br/>(Thanos / Grafana Mimir via Remote Write 2.0)"]
    end

    NE -->|"HTTP GET /metrics (Pull)"| SCRAPE
    CAD -->|"HTTP GET /metrics (Pull)"| SCRAPE
    APP -->|"HTTP POST OTLP + Exemplars"| OTLP
    SCRAPE --> WAL
    OTLP --> WAL
    WAL --> COMPACT
    WAL --> RULE
    COMPACT -->|"Remote Write 2.0"| OBJ
    RULE -->|"Push Firing Alerts"| AM
    GRAF -->|"PromQL HTTP API (/api/v1/query_range)"| PromV3

2.1. Giải phẫu Head Block, Write-Ahead Log (WAL) và Nén Chunk XOR

Mọi mẫu dữ liệu (Sample) gồm cặp (timestamp int64, value float64) hoặc cấu trúc Native Histogram khi đi vào Prometheus v3.x đều không ghi trực tiếp ra các tệp dữ liệu bất biến trên đĩa ngay lập tức mà đi qua hai thành phần:

  1. In-Memory Head Block và Write-Ahead Log (wal/): Các mẫu dữ liệu mới nhất trong cửa sổ 2 giờ gần nhất được giữ trong vùng nhớ RAM gọi là Head Block để tăng tốc độ truy vấn thời gian thực, đồng thời được ghi tuần tự xuống đĩa trong thư mục wal/ (chia thành các đoạn 128 MB) để đảm bảo khả năng khôi phục trạng thái không mất dữ liệu nếu container khởi động lại đột ngột.
  2. Nén Chunk Gorilla XOR và Memory-Mapped Chunks (chunks_head/): Khi một chuỗi thời gian trong Head Block tích lũy đủ một chunk (thường là 120 samples cho metric thông thường), Prometheus sử dụng thuật toán nén Gorilla XOR để đóng gói chunk đó và chuyển sang vùng tệp ánh xạ bộ nhớ (mmap) trong chunks_head/, giúp giảm đáng kể áp lực bộ nhớ Heap của Go runtime. Sau mỗi chu kỳ 2 giờ, trình Compactor đóng gói dữ liệu thành một thư mục khối bất biến (Immutable Block) gồm các tệp index, chunks/000001, tombstones và meta.json.

2.2. Những Đột phá Kiến trúc trên Prometheus v3.x (Baseline 2026)

So với nhánh Prometheus v2.x cũ, phiên bản Prometheus v3.x mang lại bốn nâng cấp cốt lõi cho môi trường Production năm 2026:

  • Native OTLP Ingestion (--web.enable-otlp-receiver): Prometheus v3 mở sẵn điểm cuối /api/v1/otlp/v1/metrics nhận trực tiếp dữ liệu chuẩn OpenTelemetry HTTP/Protobuf từ ứng dụng mà không bắt buộc phải dựng thêm bộ chuyển đổi trung gian.
  • Native Histograms (Biểu đồ Tần suất Nguyên bản): Thay vì phải định nghĩa trước hàng chục bucket cố định (le="0.05", le="0.1", le="0.5") làm nhân bội số lượng chuỗi thời gian, Native Histograms tự động phân bổ các bucket theo cấp số nhân với độ phân giải động và lưu toàn bộ phân phối độ trễ trong một chuỗi thời gian duy nhất trên mỗi tổ hợp nhãn.
  • Hỗ trợ UTF-8 Toàn diện: Cho phép giữ nguyên tên metric và nhãn có dấu chấm (.) hoặc ký tự đặc biệt từ chuẩn OpenTelemetry Semantic Conventions (ví dụ http.server.request.duration) mà không bắt buộc phải đổi thành dấu gạch dưới (_) nếu cấu hình translation_strategy: NoUTF8EscapingWithSuffixes.
  • Prometheus Remote Write 2.0: Tối ưu hóa băng thông mạng khi đẩy dữ liệu dài hạn sang Grafana Mimir hoặc Thanos Receive nhờ cơ chế nén bảng ký hiệu chuỗi (String Interning / Symbol Table) kèm truyền tải nguyên bản Native Histograms và Exemplars.

2.3. Công thức Định lượng Dung lượng Đĩa cho TSDB

Theo tài liệu vận hành chính thức của Prometheus, nhờ thuật toán nén XOR, mỗi mẫu dữ liệu (sample) sau khi nén chiếm trung bình khoảng 1.3 đến 2.0 bytes (và cao hơn nếu sử dụng nhiều Native Histograms hoặc churn nhãn liên tục). Kỹ sư hệ thống ước tính dung lượng ổ đĩa NVMe cần thiết theo công thức toán học:

$$text{Disk Space (Bytes)} = text{Retention Seconds} times left(frac{text{Active Series}}{text{Scrape Interval Seconds}}right) times text{Bytes per Sample}$$

Để bảo vệ máy chủ trước nguy cơ đầy phân vùng đĩa khi có đột biến số lượng container, cấu hình Production bắt buộc phải đặt đồng thời cả hai cờ giới hạn: --storage.tsdb.retention.time=15d (giới hạn theo thời gian) và --storage.tsdb.retention.size=50GB (giới hạn cứng theo dung lượng đĩa).


3. Triển khai Cụm Prometheus v3, Grafana 11, Node Exporter và Alertmanager bằng Docker Compose

Tuân thủ nguyên tắc cô lập đặc quyền và tối ưu hóa container tương tự như hướng dẫn trong bài tối ưu hóa Docker Image với Multi-stage Build và Alpine Linux, dưới đây là tệp docker-compose.yml chuẩn Production khởi chạy toàn bộ ngăn xếp Observability năm 2026:

# File: /opt/observability/docker-compose.yml
# Chuẩn Production 2026: Prometheus v3.1.0, Grafana 11.4.0, Node Exporter v1.8.2, Alertmanager v0.27.0
name: infoteck-observability-stack

networks:
  monitoring_net:
    driver: bridge
    ipam:
      config:
        - subnet: 172.28.10.0/24

volumes:
  prometheus_tsdb:
  grafana_data:
  alertmanager_data:

services:
  prometheus:
    image: prom/prometheus:v3.1.0
    container_name: prometheus-v3
    restart: unless-stopped
    user: "65534:65534" # Chạy dưới quyền người dùng không đặc quyền nobody
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--storage.tsdb.path=/prometheus"
      - "--storage.tsdb.retention.time=15d"
      - "--storage.tsdb.retention.size=50GB"
      - "--web.enable-lifecycle"
      - "--web.enable-otlp-receiver"
      - "--enable-feature=native-histograms,exemplar-storage"
    ports:
      - "127.0.0.1:9090:9090"
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - ./prometheus/rules:/etc/prometheus/rules:ro
      - prometheus_tsdb:/prometheus
    security_opt:
      - no-new-privileges:true
    networks:
      - monitoring_net
    healthcheck:
      test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:9090/-/healthy"]
      interval: 15s
      timeout: 5s
      retries: 3

  node-exporter:
    image: prom/node-exporter:v1.8.2
    container_name: node-exporter
    restart: unless-stopped
    pid: "host"
    command:
      - "--path.procfs=/host/proc"
      - "--path.sysfs=/host/sys"
      - "--path.rootfs=/rootfs"
      - "--collector.pressure"
      - "--collector.systemd"
      - "--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)"
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
      - /run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket:ro
    security_opt:
      - no-new-privileges:true
    networks:
      - monitoring_net

  alertmanager:
    image: prom/alertmanager:v0.27.0
    container_name: alertmanager
    restart: unless-stopped
    user: "65534:65534"
    command:
      - "--config.file=/etc/alertmanager/alertmanager.yml"
      - "--storage.path=/alertmanager"
      - "--cluster.listen-address="
    ports:
      - "127.0.0.1:9093:9093"
    volumes:
      - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
      - alertmanager_data:/alertmanager
    security_opt:
      - no-new-privileges:true
    networks:
      - monitoring_net
    healthcheck:
      test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:9093/-/healthy"]
      interval: 15s
      timeout: 5s
      retries: 3

  grafana:
    image: grafana/grafana:11.4.0
    container_name: grafana-v11
    restart: unless-stopped
    user: "472:472"
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      - GF_SECURITY_ADMIN_USER=${GRAFANA_ADMIN_USER:-admin}
      - GF_SECURITY_ADMIN_PASSWORD__FILE=/run/secrets/grafana_admin_password
      - GF_USERS_ALLOW_SIGN_UP=false
      - GF_SECURITY_COOKIE_SECURE=true
      - GF_SECURITY_DISABLE_GRAVATAR=true
      - GF_DASHBOARDS_DEFAULT_HOME_DASHBOARD_PATH=/var/lib/grafana/dashboards/sre-golden-signals.json
    volumes:
      - grafana_data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning:ro
      - ./grafana/dashboards:/var/lib/grafana/dashboards:ro
    depends_on:
      prometheus:
        condition: service_healthy
    security_opt:
      - no-new-privileges:true
    networks:
      - monitoring_net

[!IMPORTANT]
Nguyên tắc Bảo mật Cổng Quản trị (127.0.0.1 Binding): Tuyệt đối không phơi bày trực tiếp cổng :9090 (Prometheus, đặc biệt khi bật --web.enable-lifecycle và --web.enable-otlp-receiver) hoặc :9093 (Alertmanager) ra giao diện mạng công cộng 0.0.0.0. Hãy chỉ gắn kết vào 127.0.0.1 hoặc mạng nội bộ và đặt sau lớp xác thực Reverse Proxy mTLS / OAuth2 Proxy.


4. Cấu hình prometheus.yml với Relabeling Chống Bùng nổ Cardinality và Bật Native Histograms

Điểm khác biệt lớn nhất giữa một tệp cấu hình mẫu và tệp cấu hình Production là cơ chế metric_relabel_configs và sample_limit. Nếu một dịch vụ ứng dụng gặp lỗi sinh ra hàng trăm nghìn nhãn động, chỉ thị sample_limit: 15000 sẽ lập tức từ chối lần thu thập đó thay vì để tiến trình Prometheus bị tiêu diệt bởi cơ chế đã phân tích trong bài chẩn đoán và xử lý sự cố OOM Killer, Memory Leak trên Linux Production.

# File: /opt/observability/prometheus/prometheus.yml
global:
  scrape_interval: 15s
  scrape_timeout: 10s
  evaluation_interval: 15s
  external_labels:
    cluster: "infoteck-prod-vn-01"
    environment: "production"

# Cấu hình tiếp nhận dữ liệu chuẩn OpenTelemetry (Prometheus v3.x)
otlp:
  promote_resource_attributes:
    - service.instance.id
    - service.name
    - service.namespace
    - cloud.availability_zone
    - k8s.namespace.name
    - k8s.pod.name
  translation_strategy: UnderscoreEscapingWithSuffixes
  keep_identifying_resource_attributes: true

rule_files:
  - "/etc/prometheus/rules/*.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets:
            - "alertmanager:9093"

scrape_configs:
  # 1. Tự giám sát sức khỏe nội bộ của Prometheus v3 Server
  - job_name: "prometheus-self"
    static_configs:
      - targets: ["127.0.0.1:9090"]

  # 2. Thu thập chỉ số Kernel Linux, PSI (Pressure Stall Information) và phần cứng từ Node Exporter
  - job_name: "linux-node-exporter"
    scrape_interval: 15s
    sample_limit: 10000
    static_configs:
      - targets: ["node-exporter:9100"]
        labels:
          role: "baremetal-worker"
    metric_relabel_configs:
      # Loại bỏ các metric chi tiết từng hàng đợi mạng ảo veth không cần thiết để tiết kiệm TSDB
      - source_labels: [__name__, device]
        regex: "node_network_.*;(veth.*|cali.*|flannel.*|cbr.*)"
        action: drop

  # 3. Thu thập chỉ số ứng dụng Microservices với Native Histograms và kiểm soát Cardinality
  - job_name: "order-api-service"
    scrape_interval: 10s
    scrape_native_histograms: true
    sample_limit: 15000
    label_limit: 64
    label_name_length_limit: 128
    label_value_length_limit: 512
    static_configs:
      - targets: ["172.28.10.50:8080"]
    metric_relabel_configs:
      # Xóa các nhãn có độ phân tán cao (High-Cardinality) nếu lập trình viên vô tình xuất ra
      - regex: "(user_id|session_id|request_id|client_ip|trace_id)"
        action: labeldrop
      # Loại bỏ các metric debug nội bộ của Go runtime không phục vụ cảnh báo
      - source_labels: [__name__]
        regex: "go_memstats_(lookups_total|mallocs_total|frees_total)"
        action: drop


5. Thiết kế Truy vấn PromQL theo 4 Tín hiệu Vàng (Four Golden Signals) và Cảnh báo Multi-Burn-Rate SLO

Theo phương pháp luận Site Reliability Engineering (SRE) của Google, mọi dịch vụ Production—từ tầng cổng API cho tới cụm cơ sở dữ liệu trong bài tối ưu hóa hiệu năng MySQL 8.0 cho hệ thống triệu người dùng và tầng mạng trong bài tuning Linux Kernel cho máy chủ Web phục vụ hàng triệu kết nối đồng thời—đều phải được đo lường qua 4 Tín hiệu Vàng (Four Golden Signals): Độ trễ (Latency), Lưu lượng (Traffic), Tỷ lệ Lỗi (Errors) và Độ Bão hòa Tài nguyên (Saturation).

5.1. Bộ Truy vấn PromQL Thực chiến cho 4 Tín hiệu Vàng (Hỗ trợ cả Classic & Native Histograms)

# 1. TRAFFIC (Lưu lượng yêu cầu mỗi giây gom nhóm theo dịch vụ và phương thức HTTP)
sum by (service, method) (
  rate(http_server_requests_total{environment="production"}[5m])
)

# 2. ERRORS (Tỷ lệ lỗi HTTP 5xx trên tổng lưu lượng trong cửa sổ 5 phút)
sum by (service) (
  rate(http_server_requests_total{environment="production", status_code=~"5.."}[5m])
)
/
sum by (service) (
  rate(http_server_requests_total{environment="production"}[5m])
)

# 3A. LATENCY P99 — Cú pháp Classic Histogram (Yêu cầu gom nhóm theo nhãn `le`)
histogram_quantile(
  0.99,
  sum by (service, le) (
    rate(http_server_request_duration_seconds_bucket{environment="production"}[5m])
  )
)

# 3B. LATENCY P99 — Cú pháp Native Histogram trên Prometheus v3.x (Không cần nhãn `le`)
histogram_quantile(
  0.99,
  sum by (service) (
    rate(http_server_request_duration_seconds{environment="production"}[5m])
  )
)

# 4. SATURATION — Độ bão hòa Bộ nhớ Thực tế và Áp lực Chờ đợi Bộ nhớ Linux PSI (Kernel 6.12 LTS)
# 4a. Phần trăm bộ nhớ khả dụng thực tế trên máy chủ Linux:
(
  1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)
) * 100

# 4b. Tỷ lệ thời gian tiến trình bị đình trệ hoàn toàn do thiếu RAM (Linux PSI Full Stall Ratio):
rate(node_pressure_memory_waiting_seconds_total[5m])

5.2. Luồng Đánh giá Cảnh báo Multi-Window Multi-Burn-Rate SLO và Alertmanager

Thay vì cảnh báo mỗi khi có vài request lỗi thoáng qua, kiến trúc Multi-Window Multi-Burn-Rate Alerting đo tốc độ tiêu thụ ngân sách lỗi (Burn Rate). Với mục tiêu SLO = 99.9% trong chu kỳ 30 ngày, ngân sách lỗi cho phép là 0.1% (1 - 0.999 = 0.001, tương đương 43.2 phút ngừng hoạt động mỗi 30 ngày):

  • Tốc độ đốt cháy Burn Rate = 1x: Nếu tỷ lệ lỗi duy trì ở mức 0.001 (0.1%), toàn bộ ngân sách lỗi sẽ cạn kiệt sau đúng 30 ngày (720 giờ).
  • Tốc độ đốt cháy khẩn cấp Burn Rate = 14.4x (Page / Đánh thức Kỹ sư Trực): Ngân sách lỗi 30 ngày sẽ bị thiêu rụi hoàn toàn chỉ trong 50 giờ (2% ngân sách biến mất trong 1 giờ). Khi cả cửa sổ dài 1h và cửa sổ ngắn 5m đồng thời vượt ngưỡng 14.4 * 0.001 = 0.0144 (1.44% lỗi), Prometheus phát cảnh báo severity: critical. Cửa sổ ngắn 5m đảm bảo cảnh báo tự động tắt ngay khi sự cố vừa được khắc phục.
  • Tốc độ đốt cháy trung bình Burn Rate = 6x (Ticket / Xử lý Trong Giờ Làm Việc): Ngân sách lỗi 5% bị tiêu hao trong 6 giờ (kiểm tra đồng thời trên cửa sổ 6h và 30m, ngưỡng lỗi 6 * 0.001 = 0.006).

sequenceDiagram
    autonumber
    participant TargetApp as Microservices & Node Exporter
    participant PromV3 as Prometheus v3 TSDB
    participant RuleEng as PromQL Rule Engine
    participant AlertMgr as Alertmanager v0.27
    participant Grafana11 as Grafana 11 UI
    participant OnCallSRE as Kỹ sư SRE Trực chiến

    TargetApp->>PromV3: Thu thập /metrics (10s) & nhận OTLP Metrics + Exemplars
    PromV3->>RuleEng: Đánh giá Recording Rules & SLO Burn-Rate mỗi 15s
    RuleEng->>RuleEng: Kiểm tra Burn Rate 1h > 14.4x VÀ 5m > 14.4x (for: 2m)
    RuleEng->>AlertMgr: Đẩy cảnh báo trạng thái FIRING (severity=critical)
    AlertMgr->>AlertMgr: Gom nhóm theo cluster, service & áp dụng Inhibit Rules
    AlertMgr->>OnCallSRE: Gửi cảnh báo PagerDuty / Slack kèm Runbook URL
    OnCallSRE->>Grafana11: Truy cập Dashboard & nhấn vào điểm Exemplar trên biểu đồ P99
    Grafana11->>PromV3: Truy vấn chi tiết nhãn & TraceID gắn với yêu cầu lỗi

5.3. Cấu hình Recording Rules & Multi-Burn-Rate Alerting Rules (rules/slo-burn-rate-alerts.yml)

Sử dụng Recording Rules để tính toán trước tỷ lệ lỗi theo quy ước đặt tên chuẩn level:metric:operations giúp giảm tải CPU khi Grafana truy vấn và giữ cho biểu thức cảnh báo rõ ràng, dễ kiểm toán:

# File: /opt/observability/prometheus/rules/slo-burn-rate-alerts.yml
groups:
  - name: slo_http_error_recording_rules
    interval: 15s
    rules:
      # Tính trước tỷ lệ lỗi 5xx trên các cửa sổ 5m, 30m, 1h, 6h
      - record: service:http_requests_error_ratio:rate5m
        expr: |
          sum by (service) (rate(http_server_requests_total{status_code=~"5.."}[5m]))
          /
          sum by (service) (rate(http_server_requests_total[5m]))

      - record: service:http_requests_error_ratio:rate30m
        expr: |
          sum by (service) (rate(http_server_requests_total{status_code=~"5.."}[30m]))
          /
          sum by (service) (rate(http_server_requests_total[30m]))

      - record: service:http_requests_error_ratio:rate1h
        expr: |
          sum by (service) (rate(http_server_requests_total{status_code=~"5.."}[1h]))
          /
          sum by (service) (rate(http_server_requests_total[1h]))

      - record: service:http_requests_error_ratio:rate6h
        expr: |
          sum by (service) (rate(http_server_requests_total{status_code=~"5.."}[6h]))
          /
          sum by (service) (rate(http_server_requests_total[6h]))

  - name: slo_multi_burn_rate_alerts
    rules:
      # Cảnh báo Khẩn cấp (Page): Tốc độ đốt Error Budget 14.4x trên cả cửa sổ 1h và 5m (SLO 99.9%)
      - alert: SLOHighErrorBurnRateCritical
        expr: |
          (
            service:http_requests_error_ratio:rate1h > (14.4 * 0.001)
            and
            service:http_requests_error_ratio:rate5m > (14.4 * 0.001)
          )
        for: 2m
        labels:
          severity: critical
          slo_tier: "tier-1"
        annotations:
          summary: "Dịch vụ {{ $labels.service }} đang đốt Error Budget ở tốc độ khẩn cấp (> 14.4x)"
          description: "Tỷ lệ lỗi HTTP 5xx hiện tại của {{ $labels.service }} là {{ $value | humanizePercentage }}, vượt ngưỡng SLO 99.9% trên cả cửa sổ 1h và 5m."
          runbook_url: "https://infoteck.vn/xay-dung-cicd-pipeline-github-actions-docker/"

      # Cảnh báo Sớm Dự đoán Đầy Ổ Đĩa trong vòng 24 giờ tới bằng hàm predict_linear()
      - alert: HostDiskWillFillIn24Hours
        expr: |
          (
            node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"} < 0.20
          )
          and
          (
            predict_linear(node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"}[6h], 24 * 3600) < 0
          )
        for: 15m
        labels:
          severity: warning
        annotations:
          summary: "Phân vùng {{ $labels.mountpoint }} trên {{ $labels.instance }} dự kiến đầy trong < 24 giờ"
          description: "Dung lượng trống hiện dưới 20% và tốc độ ghi 6h qua cho thấy ổ đĩa sẽ cạn kiệt trong vòng 24 giờ tới."


6. Cấu hình Định tuyến Cảnh báo (alertmanager.yml) và Tự động Khởi tạo Grafana 11 (Provisioning-as-Code)

6.1. Thiết lập Cây Định tuyến và Cơ chế Triệt tiêu Cảnh báo Hệ quả (inhibit_rules) trên Alertmanager

Khi một máy chủ vật lý mất kết nối mạng hoặc sập nguồn (severity: critical), hàng chục cảnh báo mức warning của các container bên trên máy chủ đó cũng sẽ đồng loạt kích hoạt. Cơ chế inhibit_rules trong alertmanager.yml tự động khóa các cảnh báo mức warning trùng nhãn cluster và service, giúp kỹ sư trực chiến chỉ nhận đúng 1 thông báo gốc duy nhất:

# File: /opt/observability/alertmanager/alertmanager.yml
global:
  resolve_timeout: 5m

route:
  receiver: "sre-default-webhook"
  group_by: ["cluster", "alertname", "service"]
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  routes:
    - matchers:
        - severity = "critical"
      receiver: "sre-oncall-critical"
      group_wait: 10s
      repeat_interval: 1h

inhibit_rules:
  # Nếu đã có cảnh báo mức critical đang kích hoạt cho cùng một cluster và service,
  # tự động tạm ẩn các cảnh báo mức warning của dịch vụ đó để chống bão thông báo.
  - source_matchers:
      - severity = "critical"
    target_matchers:
      - severity = "warning"
    equal: ["cluster", "service"]

receivers:
  - name: "sre-default-webhook"
    webhook_configs:
      - url: "http://127.0.0.1:5001/alerts/general"
        send_resolved: true

  - name: "sre-oncall-critical"
    webhook_configs:
      - url: "http://127.0.0.1:5001/alerts/critical-pager"
        send_resolved: true

6.2. Khởi tạo Datasource và Dashboard Tự động trên Grafana 11.x (GitOps Provisioning)

Thay vì bấm chuột tạo từng biểu đồ thủ công trên giao diện web (dễ mất trắng khi tạo lại container và không thể kiểm soát lịch sử thay đổi trên Git như trong quy trình xây dựng CI/CD Pipeline với GitHub Actions và Docker), Grafana 11.x hỗ trợ khai báo toàn bộ cấu hình qua thư mục /etc/grafana/provisioning/:

# File: /opt/observability/grafana/provisioning/datasources/prometheus.yml
apiVersion: 1

datasources:
  - name: "Prometheus-v3-Production"
    uid: "prom_prod_v3"
    type: prometheus
    access: proxy
    url: "http://prometheus:9090"
    isDefault: true
    editable: false
    jsonData:
      httpMethod: POST
      timeInterval: "15s"
      queryTimeout: "60s"
      prometheusType: Prometheus
      prometheusVersion: "3.1.0"
      exemplarTraceIdDestinations:
        - name: trace_id
          url: "https://grafana.infoteck.internal/explore?left=%5B%22now-1h%22,%22now%22,%22Tempo%22,%7B%22query%22:%22$${__value.raw}%22%7D%5D"


7. Quy trình Kiểm định Cú pháp (promtool / amtool), Kiểm tra Cardinality và Xử lý Sự cố

Trước khi áp dụng bất kỳ thay đổi nào lên hệ thống giám sát Production, kỹ sư SRE bắt buộc phải chạy bộ lệnh kiểm chứng tĩnh bằng promtool và amtool đi kèm trong chính Docker image để đảm bảo không có lỗi cú pháp YAML hay biểu thức PromQL làm gián đoạn dịch vụ:

#!/usr/bin/env bash
# File: /opt/observability/verify-and-reload.sh
# Mô tả: Kiểm tra tính hợp lệ của cấu hình Prometheus v3, Alert Rules, Alertmanager và nạp lại không gián đoạn (Zero-Downtime Reload)
set -euo pipefail

echo "=== [1/4] Kiểm tra cú pháp prometheus.yml và slo-burn-rate-alerts.yml bằng promtool ==="
docker exec prometheus-v3 promtool check config /etc/prometheus/prometheus.yml
docker exec prometheus-v3 promtool check rules /etc/prometheus/rules/slo-burn-rate-alerts.yml

echo "=== [2/4] Kiểm tra cây định tuyến alertmanager.yml bằng amtool ==="
docker exec alertmanager amtool check-config /etc/alertmanager/alertmanager.yml

echo "=== [3/4] Kích hoạt Hot-Reload cấu hình Prometheus v3 không gây downtime ==="
curl -fsS -X POST http://127.0.0.1:9090/-/reload
curl -fsS -X POST http://127.0.0.1:9093/-/reload

echo "=== [4/4] Truy vấn API TSDB Status để kiểm tra Top 10 Metric chiếm nhiều chuỗi thời gian nhất ==="
curl -fsS http://127.0.0.1:9090/api/v1/status/tsdb | grep -o '"seriesCountByMetricName":[[^]]*]' | head -c 600
echo ""

Bảng Chẩn đoán Nhanh Các Sự cố Thường gặp trên Production

Triệu chứng Sự cố Nguyên nhân Gốc rễ (Root Cause) Giải pháp Khắc phục Triệt để
Biểu đồ Grafana xuất hiện các khoảng đứt đoạn (Gaps) khi phóng to khung 5 phút Giá trị timeInterval trong Datasource của Grafana đặt nhỏ hơn scrape_interval thực tế trong prometheus.yml, khiến hàm rate($__rate_interval) chỉ bắt được 0 hoặc 1 mẫu dữ liệu trong cửa sổ. Đồng bộ hóa jsonData.timeInterval: "15s" trên Grafana khớp chính xác với scrape_interval: 15s của Prometheus và luôn sử dụng biến [$__rate_interval] trong mọi truy vấn rate() / increase().
Dung lượng RAM của container prometheus-v3 tăng vọt liên tục Hiện tượng Series Churn hoặc High Cardinality: Nhãn chứa ID động (pod_uid, session_id, URL query string) tạo ra hàng triệu chuỗi mới trong Head Block mỗi giờ. Truy cập /tsdb-status trên giao diện Prometheus hoặc API /api/v1/status/tsdb để xác định nhãn gây phình to, sau đó thêm quy tắc action: labeldrop vào metric_relabel_configs và đặt sample_limit.
Thời gian khởi động lại Prometheus kéo dài nhiều phút Quá trình phát lại nhật ký WAL Replay phải đọc qua nhiều phân đoạn wal/ lớn nếu lần tắt trước đó bị ép dừng (SIGKILL) trước khi kịp ghi Checkpoint. Đảm bảo stop_grace_period: 2m trong Docker Compose để Prometheus kịp đóng gói dữ liệu an toàn khi nhận tín hiệu SIGTERM, và lưu thư mục /prometheus trên ổ cứng NVMe có IOPS cao.

8. Tài liệu Tham khảo & Nguồn Đối chiếu Chính thống (Primary References)

  1. Prometheus Official Documentation (v3.x Migration & Native OTLP / Native Histograms Guide): https://prometheus.io/docs/prometheus/latest/migration/
  2. Prometheus Local Storage & TSDB Format Specification: https://prometheus.io/docs/prometheus/latest/storage/
  3. Google Site Reliability Engineering (SRE) Workbook — Chapter 5: Alerting on SLOs (Multi-Window, Multi-Burn-Rate Alerts): https://sre.google/workbook/alerting-on-slos/
  4. Grafana 11.x Official Documentation — Provisioning Datasources and Dashboards as Code: https://grafana.com/docs/grafana/latest/administration/provisioning/
  5. Prometheus Alertmanager Configuration & Inhibition Rules Specification: https://prometheus.io/docs/alerting/latest/configuration/