Cuộc gọi lúc 2 giờ sáng và những con số ‘vô tri’
Điện thoại mình rung bần bật trên bàn lúc nửa đêm. Slack tràn ngập thông báo 504 Gateway Timeout. Khi check log ứng dụng, mình chỉ thấy một hàng dài lỗi Connection pool exhausted. Mình vội vã SSH vào server, gõ top thì thấy CPU nhảy vọt lên 90%, nhưng tuyệt nhiên không biết query nào đang ‘ngốn’ tài nguyên hay có bao nhiêu transaction đang bị treo.
Cảm giác lúc đó giống như lái xe tốc độ cao trong sương mù mà không có đèn pha. Nếu có hệ thống giám sát đủ tốt, mình đã nhận ra số lượng connection tăng đột biến từ lúc 1h45 để xử lý trước khi hệ thống ‘sụp đổ’. Bài viết này là đúc kết từ những lần ‘ăn hành’ đó, giúp bạn xây dựng một ‘cặp mắt’ sắc bén cho PostgreSQL.
Triển khai nhanh: Có ngay Dashboard sau 5 phút
Để debug nhanh hoặc thử nghiệm, Docker Compose là lựa chọn tối ưu nhất. Chỉ với một file cấu hình, bạn sẽ dựng được toàn bộ stack giám sát mà không cần cài đặt rườm rà.
# docker-compose.yml
version: '3.8'
services:
postgres_exporter:
image: prometheuscommunity/postgres-exporter
environment:
DATA_SOURCE_NAME: "postgresql://user:password@your_db_ip:5432/postgres?sslmode=disable"
ports:
- "9187:9187"
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
grafana:
image: grafana/grafana
ports:
- "3000:3000"
Tiếp theo, hãy tạo file prometheus.yml với cấu hình tối giản để nhận dữ liệu:
scrape_configs:
- job_name: 'postgres'
static_configs:
- targets: ['postgres_exporter:9187']
Chạy lệnh docker-compose up -d. Lúc này, exporter sẽ bắt đầu thu thập metrics, đẩy về Prometheus và sẵn sàng để hiển thị trực quan trên Grafana tại cổng 3000.
Cơ chế hoạt động: Vai trò của postgres_exporter
PostgreSQL không mặc định xuất dữ liệu theo định dạng time-series mà Prometheus yêu cầu. postgres_exporter đóng vai trò như một thông dịch viên. Nó truy cập vào Database, thực thi các câu lệnh SQL như SELECT * FROM pg_stat_activity, sau đó chuyển đổi kết quả thành các metrics máy tính có thể hiểu được.
Thiết lập User riêng để bảo mật
Đừng bao giờ dùng tài khoản postgres (superuser) cho việc giám sát trên production. Bạn nên tạo một user riêng với quyền hạn hạn chế để đảm bảo an toàn:
-- Tạo user chuyên biệt cho monitoring
CREATE USER monitoring WITH PASSWORD 'your_secure_password';
-- Cấp quyền truy cập các bảng thống kê hệ thống
GRANT pg_monitor TO monitoring;
4 chỉ số ‘vàng’ bạn không thể bỏ qua
Đừng để bị ngợp bởi hàng trăm biểu đồ. Hãy tập trung vào các con số thực sự phản ánh sức khỏe hệ thống:
- Connections: So sánh số kết nối thực tế với
max_connections. Nếu con số này chạm ngưỡng 80%, hệ thống của bạn đang nằm trong vùng nguy hiểm. - Transaction Throughput: Theo dõi tỉ lệ Commit/Rollback. Nếu Rollback tăng vọt (ví dụ > 5%), có thể code ứng dụng đang gặp lỗi logic hoặc tranh chấp dữ liệu.
- Buffer Cache Hit Ratio: Tỉ lệ dữ liệu đọc từ RAM. Con số này cần duy trì trên 95%. Nếu giảm xuống 80%, Disk I/O sẽ tăng gấp 10 lần, khiến DB chậm đi trông thấy.
- Database Size & Bloat: Theo dõi độ phình của table. Một bảng 10GB có thể chứa tới 4GB ‘rác’ (dead tuples) nếu tiến trình Autovacuum không hoạt động hiệu quả.
Trong quá trình vận hành, đôi khi bạn cần trích xuất nhanh dữ liệu từ SQL sang các định dạng khác để báo cáo. Mình thường dùng công cụ convert CSV sang JSON tại toolcraft.app. Điểm cộng là nó xử lý ngay trên trình duyệt, không lo lộ dữ liệu nhạy cảm lên server bên thứ ba.
Thiết lập Alerts: Để bạn luôn ngủ ngon giấc
Dashboard chỉ có ích khi bạn nhìn vào nó. Nhưng bạn không thể dán mắt vào màn hình 24/7. Alerting chính là người gác đền giúp bạn phản ứng kịp thời trước khi thảm họa xảy ra.
Cấu hình Alert Rule mẫu
Tạo file alert_rules.yml để định nghĩa các ngưỡng cảnh báo:
groups:
- name: postgres_alerts
rules:
- alert: PostgresHighConnections
expr: pg_stat_database_numbackends > (pg_settings_max_connections * 0.8)
for: 5m
labels:
severity: critical
annotations:
summary: "DB sắp hết connection trên {{ $labels.instance }}"
description: "Số lượng kết nối vượt 80% giới hạn trong 5 phút liên tục."
- alert: PostgresDown
expr: pg_up == 0
for: 1m
labels:
severity: fatal
annotations:
summary: "PostgreSQL sập rồi!"
description: "Không thể kết nối tới instance {{ $labels.instance }}. Kiểm tra ngay!"
Khi tích hợp với Slack hoặc Telegram, bạn sẽ nhận được tin nhắn ngay khi connection bắt đầu tăng. Việc kill bớt các ‘idle connections’ lúc này dễ dàng hơn nhiều so với việc cứu một DB đã treo hoàn toàn.
Kinh nghiệm thực chiến khi triển khai
Sau nhiều lần xử lý sự cố cho các hệ thống lớn, mình rút ra vài lưu ý quan trọng:
- Tận dụng Dashboard cộng đồng: Đừng tự vẽ Dashboard từ con số 0. Hãy vào Grafana Labs và import Dashboard ID
9628. Đây là bản chuẩn hóa được cộng đồng tin dùng nhất. - Tần suất lấy dữ liệu (Scraping Interval): Tránh đặt mức 1 giây/lần vì mỗi lần lấy metrics là một lần query vào DB. Khoảng cách 15-30 giây là điểm cân bằng hoàn hảo giữa độ chính xác và hiệu năng.
- Giám sát cả phần cứng: DB chậm đôi khi do nghẽn cổ chai I/O đĩa cứng. Hãy cài thêm
node_exporterđể theo dõi song song cả CPU, RAM và Disk latency của server. - Kết hợp pg_stat_statements: Prometheus cho biết DB đang chậm, nhưng
pg_stat_statementsmới chỉ ra chính xác câu SQL nào là thủ phạm. Hãy bật extension này để đào sâu dữ liệu.
Thiết lập giám sát có thể tốn của bạn vài giờ ban đầu, nhưng nó sẽ tiết kiệm hàng tuần lễ mò mẫm trong log sau này. Một hệ thống chuyên nghiệp không chỉ chạy tốt, mà còn phải đo lường được.

