Khi dashboard ‘xanh’ nhưng hệ thống vẫn ‘ngỏm’
Chuông PagerDuty réo lúc 2 giờ sáng. Mình bật dậy, dụi mắt nhìn Dashboard Grafana: CPU 20%, RAM dư dả, Node Exporter báo mọi thứ vẫn ổn. Thế nhưng, group chat hỗ trợ khách hàng đang nổ tung vì 500 người dùng không thể thanh toán.
Sau 30 phút rà soát, mình phát hiện một API nội bộ trả về lỗi 500. Hơn 1.200 đơn hàng bị kẹt ở trạng thái ‘Pending’. Prometheus hoàn toàn mù tịt vì nó chỉ giám sát hạ tầng, không chạm được vào logic nghiệp vụ bên trong.
Trước đây, mình thường SSH vào server để tail -f log hoặc chạy SQL đếm lỗi thủ công. Cách này cực kỳ tốn sức. Nếu không tìm cách ‘phơi’ (expose) dữ liệu nghiệp vụ ra Prometheus, bạn sẽ còn thức trắng đêm dài dài.
Tại sao Node Exporter là chưa đủ?
Các công cụ như node_exporter hay mysql_exporter rất mạnh nhưng có một giới hạn: Chúng không hiểu nghiệp vụ của bạn.
Hãy tưởng tượng một hệ thống Core Banking cũ từ 10 năm trước. Nó không có endpoint /metrics. Nó chỉ trả về JSON hoặc ghi log vào file. Prometheus cần dữ liệu định dạng text đặc thù. Nếu hệ thống không ‘nói’ cùng ngôn ngữ, Prometheus sẽ chịu chết.
Bạn sẽ cần một giải pháp tùy biến khi:
- Dữ liệu nằm trong API nội bộ chỉ trả về JSON thô.
- Cần đếm số đơn hàng bị treo quá 5 phút trong Database.
- Theo dõi số lượng người dùng thực tế đang login vào hệ thống.
Ba hướng tiếp cận phổ biến
Mình từng cân nhắc ba phương án để giải quyết bài toán này:
- Textfile Collector: Viết script chạy cronjob rồi xuất file .prom. Cách này đơn giản nhưng khó quản lý khi hệ thống phình to.
- Pushgateway: Đẩy dữ liệu lên một trạm trung chuyển. Phương án này hợp với các job chạy ngắn hạn (batch jobs). Tuy nhiên, nếu script chết mà Pushgateway không biết, bạn sẽ nhận dữ liệu ‘rác’.
- Custom Exporter (Khuyên dùng): Xây dựng một service nhỏ (sidecar) bằng Python. Nó lấy dữ liệu, chuyển sang chuẩn Prometheus và đợi Prometheus đến lấy (pull). Đây là cách ổn định nhất cho môi trường Production.
Thực hành: Viết Custom Exporter bằng Python
Python là lựa chọn số một nhờ thư viện prometheus_client rất dễ dùng. Chúng ta sẽ viết một exporter lấy dữ liệu từ API giả lập.
Bước 1: Cài đặt công cụ
Tạo môi trường ảo và cài đặt thư viện cần thiết:
pip install prometheus_client requests
Bước 2: Viết mã nguồn
Giả sử API /status trả về pending_orders: 42 và active_users: 150. Dưới đây là code để chuyển đổi chúng:
import time
import requests
from prometheus_client import start_http_server, Gauge
# Khởi tạo Metric: Gauge cho phép tăng/giảm giá trị
PENDING_ORDERS = Gauge('myapp_pending_orders', 'Số đơn hàng đang chờ')
ACTIVE_USERS = Gauge('myapp_active_users', 'Số người dùng online')
def fetch_metrics():
try:
# Giả lập gọi API thực tế
# resp = requests.get("http://api.internal/status", timeout=5)
# data = resp.json()
data = {"pending_orders": 42, "active_users": 150}
# Đẩy dữ liệu vào Prometheus Client
PENDING_ORDERS.set(data['pending_orders'])
ACTIVE_USERS.set(data['active_users'])
print(f"Updated: {data['pending_orders']} orders")
except Exception as e:
print(f"Lỗi fetch dữ liệu: {e}")
if __name__ == '__main__':
# Mở port 8000 để Prometheus vào lấy dữ liệu
start_http_server(8000)
while True:
fetch_metrics()
time.sleep(15) # Cập nhật mỗi 15 giây
Bước 3: Cấu hình Prometheus
Thêm vài dòng sau vào file prometheus.yml để kết nối:
scrape_configs:
- job_name: 'python_exporter'
static_configs:
- targets: ['localhost:8000']
Sau khi restart Prometheus, bạn có thể vẽ biểu đồ trên Grafana ngay lập tức.
Kinh nghiệm ‘xương máu’ khi triển khai
Để exporter không làm sập hệ thống, bạn cần lưu ý 3 điểm sau:
- Luôn dùng Timeout: Khi gọi API bằng
requests, hãy settimeout=5. Nếu API treo, exporter của bạn cũng sẽ ‘ngỏm’ theo. - Khớp tần suất Scrape: Nếu Prometheus lấy dữ liệu mỗi 15 giây, script của bạn cũng nên chạy mỗi 15 giây. Đừng gọi API quá dày đặc gây lãng phí tài nguyên.
- Quản lý bằng Systemd: Đừng chạy script bằng tay. Hãy dùng Systemd để nó tự khởi động lại khi server reboot hoặc script bị crash.
Ví dụ file Systemd (/etc/systemd/system/my_exporter.service):
[Service]
ExecStart=/usr/bin/python3 /opt/exporter.py
Restart=always
User=prometheus
Giờ đây, thay vì thức trắng đêm, mình chỉ cần cài Alert trên Grafana. Nếu myapp_pending_orders > 100 trong 2 phút, Telegram sẽ báo ngay. Bạn có thể xử lý sự cố từ xa mà không cần mở laptop. Đó là giá trị thực sự của việc giám sát ‘may đo’ theo nhu cầu.

