Giám sát Database với Prometheus & Grafana: Hướng dẫn Thực tế

Database tutorial - IT technology blog
Database tutorial - IT technology blog

Cuộc gọi đánh thức lúc 2 giờ sáng

Lúc đó là 2:14 sáng. Điện thoại của tôi rung bần bật trên tủ đầu giường với cảnh báo từ PagerDuty chỉ vỏn vẹn một dòng: API Latency > 5s. Bản năng đầu tiên của tôi là kiểm tra log ứng dụng, nhưng mọi thứ trông vẫn ổn. CPU trên các web server đang ở mức sử dụng 15% khá dễ chịu. Sau đó, tôi kiểm tra các chỉ số (metrics) của database. Tranh chấp khóa (lock contention) đang ở mức cao. Một script migration cũ đang giữ metadata lock trên bảng hoạt động mạnh nhất hệ thống, và các yêu cầu đang dồn ứ lại như một vụ tai nạn liên hoàn trên đường cao tốc.

Nếu không có một hệ thống giám sát (monitoring stack) vững chắc, tôi chắc chắn đã phải mất hai giờ tiếp theo để theo dõi log và đoán mò. Cho dù bạn sử dụng MySQL, PostgreSQL hay MongoDB, những cơ sở dữ liệu này đều có một đặc điểm chung: chúng gặp lỗi một cách âm thầm cho đến khi toàn bộ ứng dụng bị đình trệ. Hướng dẫn này sẽ đi sâu vào việc thiết lập một quy trình giám sát đã được kiểm chứng qua thực tế bằng cách sử dụng Prometheus và Grafana. Mục tiêu của chúng ta là phát hiện những vấn đề này khi chúng còn là những trục trặc nhỏ, chứ không phải khi đã trở thành sự cố ngừng hoạt động hoàn toàn.

Bắt đầu nhanh: Vận hành trong 5 phút

Nếu bạn cần khả năng quan sát ngay lập tức, mô hình “Exporter” là lựa chọn tốt nhất. Prometheus không giao tiếp trực tiếp với database. Thay vào đó, nó thu thập (scrape) metrics từ một exporter—một dịch vụ sidecar nhỏ có nhiệm vụ chuyển đổi các thông số nội bộ của database sang định dạng mà Prometheus có thể hiểu được.

1. Triển khai Exporter

Đối với PostgreSQL, hãy sử dụng postgres_exporter. Đối với MySQL, mysqld_exporter là tiêu chuẩn. Dưới đây là một đoạn mã docker-compose.yml để chạy exporter cho PostgreSQL cùng với database của bạn ngay lập tức:

services:
  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: password123

  postgres-exporter:
    image: prometheuscommunity/postgres-exporter
    environment:
      DATA_SOURCE_NAME: "postgresql://postgres:password123@db:5432/postgres?sslmode=disable"
    ports:
      - "9187:9187"

2. Cấu hình Prometheus

Tiếp theo, hãy cập nhật tệp prometheus.yml của bạn. Điều này chỉ cho Prometheus biết nơi để lấy dữ liệu thô sau mỗi vài giây.

scrape_configs:
  - job_name: 'postgres_metrics'
    static_configs:
      - targets: ['postgres-exporter:9187']

3. Import Dashboard

Sau khi Prometheus bắt đầu kéo dữ liệu, hãy mở Grafana và thêm Prometheus làm data source. Thay vì xây dựng biểu đồ từ đầu, hãy import Dashboard ID 9628 cho Postgres hoặc 7362 cho MySQL. Bạn sẽ ngay lập tức thấy cái nhìn trực quan về sức khỏe của database.

Đi sâu tìm hiểu: Cách hệ thống giám sát thực sự vận hành

Triển khai công cụ thì dễ, nhưng bạn cần hiểu kiến trúc bên dưới để xử lý sự cố hiệu quả khi có vấn đề phát sinh. Hệ thống tuân theo mô hình pull-based, trong đó Prometheus đóng vai trò là bộ thu thập dữ liệu chủ động.

Vai trò của Exporter

Exporter đóng vai trò như một thông dịch viên. Nó chạy các truy vấn SQL đối với các bảng thống kê nội bộ của database. Trong PostgreSQL, nó nhìn vào pg_stat_activity; trong MySQL, nó truy cập vào performance_schema. Các exporter này cung cấp một endpoint /metrics mà Prometheus sẽ scrape định kỳ theo khoảng thời gian có thể cấu hình, thường là mỗi 15 đến 60 giây.

Các chỉ số quan trọng cần theo dõi

Đừng cố gắng giám sát mọi biến số có thể. Hãy tập trung vào những “Tín hiệu Vàng” (Golden Signals) này để giữ cho đầu óc tỉnh táo:

  • Connections (Kết nối): Bạn có đang tiến gần đến giới hạn max_connections không? Nếu DB của bạn cho phép 100 kết nối và bạn chạm mức 98, ứng dụng của bạn sẽ bắt đầu báo lỗi “Connection Refused” ngay lập tức.
  • Buffer Cache Hit Ratio: Đối với Postgres, hãy đặt mục tiêu từ 99% trở lên. Nếu con số này giảm xuống 90%, database của bạn đang đọc dữ liệu từ đĩa thay vì RAM. Sự thay đổi này có thể biến một truy vấn 1ms thành một cơn ác mộng 100ms.
  • Transaction ID Wraparound (Postgres): Đây là kẻ giết người thầm lặng nguy hiểm nhất. Nếu chỉ số này đạt đến giới hạn, database sẽ dừng chấp nhận các lệnh ghi để ngăn chặn việc hỏng dữ liệu.
  • Slow Queries (Truy vấn chậm): Theo dõi các truy vấn mất hơn 500ms. Đây thường là dấu hiệu đầu tiên của việc thiếu index.

Sử dụng nâng cao: Custom Metrics và Cảnh báo

Các exporter tiêu chuẩn rất tốt cho sức khỏe phần cứng, nhưng chúng không hiểu logic kinh doanh của bạn. Bạn có thể cần biết có bao nhiêu “Thanh toán chưa xử lý” (Unprocessed Payments) đang nằm trong một bảng, vì sự gia tăng đột ngột ở đó cho thấy các background worker của bạn đang gặp lỗi.

Truy vấn tùy chỉnh với SQL Exporter

sql_exporter là công cụ hoàn hảo cho việc này. Nó cho phép bạn biến bất kỳ câu lệnh SQL SELECT COUNT(*) nào thành một Prometheus gauge mà không cần viết một dòng mã Go hay Python nào.

# custom_queries.yml
jobs:
  - name: "business_metrics"
    interval: "1m"
    queries:
      - name: "unprocessed_orders"
        help: "Các đơn hàng bị kẹt ở trạng thái pending"
        values: [count]
        query: "SELECT count(*) as count FROM orders WHERE status = 'pending';"

Thiết lập Cảnh báo (Alerts)

Giám sát sẽ vô nghĩa nếu bạn phải dán mắt vào màn hình cả ngày. Bạn cần Prometheus Alertmanager để thực hiện các công việc nặng nhọc. Đây là một quy tắc tôi sử dụng để phát hiện sự tăng vọt kết nối trước khi chúng làm sập ứng dụng:

groups:
- name: database_alerts
  rules:
  - alert: HighConnectionCount
    expr: pg_stat_database_numbackends > 80
    for: 2m
    labels:
      severity: warning
    annotations:
      summary: "Số lượng kết nối cao trên {{ $labels.instance }}"
      description: "Kết nối database đang ở mức {{ $value }}, vượt quá 80% dung lượng trong hơn 2 phút."

Kinh nghiệm thực tế cho môi trường Production

Sau nhiều năm quản lý các cluster production, tôi nhận ra rằng một hệ thống giám sát cấu hình kém cũng nguy hiểm không kém gì việc không có giám sát. Sau đây là cách để giữ an toàn.

Đừng để cửa chính mở toang

Các exporter thường chạy với quyền đọc cấp cao đối với metadata của bạn. Đừng bao giờ công khai các cổng của exporter như 9187 lên internet. Hãy sử dụng một VPC riêng tư hoặc mô hình Kubernetes sidecar để chỉ Prometheus mới có thể truy cập endpoint. Luôn tạo một user riêng biệt, bị hạn chế quyền cho exporter:

-- Dành cho PostgreSQL 10 trở lên
CREATE USER monitoring WITH PASSWORD 'su_dung_mat_khau_manh';
GRANT pg_monitor TO monitoring;

Tránh bẫy “Thu thập quá đà” (Over-Scraping)

Thu thập dữ liệu mỗi 1 giây nghe có vẻ là một ý tưởng hay để có dữ liệu độ phân giải cao, nhưng thường là quá mức cần thiết. Việc truy vấn các schema hiệu năng sẽ gây thêm tải đáng kể cho CPU. Đối với hầu hết các khối lượng công việc production, khoảng thời gian 15 hoặc 30 giây là đủ chi tiết mà không ảnh hưởng đến hiệu suất truy vấn.

Khắc phục tình trạng mệt mỏi vì Dashboard

Tôi đã thấy các team có tới 50 biểu đồ khác nhau trên một trang duy nhất. Khi xảy ra sự cố, họ bị đóng băng vì không biết biểu đồ nào mới thực sự quan trọng. Hãy sắp xếp các Grafana dashboard theo mức độ ưu tiên. Giữ một dashboard “Tóm tắt điều hành” (Executive Summary) chỉ với trạng thái xanh/đỏ của các cluster, và liên kết đến các dashboard “Đi sâu” (Deep Dive) để xử lý sự cố chi tiết.

Giám sát hiệu quả cuối cùng là để bạn có thể ngủ ngon hơn. Bạn càng tự động hóa việc phát hiện các điểm nghẽn bao nhiêu, bạn càng mất ít thời gian để đóng vai thám tử lúc 2 giờ sáng bấy nhiêu. Hãy bắt đầu với các exporter cơ bản, tinh chỉnh cảnh báo và hoàn thiện hệ thống khi bạn dần hiểu được những đặc thù riêng trong lưu lượng truy cập của mình.

Share: