Cảnh báo lúc 2 giờ sáng và những đêm “mò mẫm” log
Hồi mới vận hành các cụm Microservices Java, mình sợ nhất là nhận tin nhắn báo hệ thống sập lúc nửa đêm. Lúc đó, việc đầu tiên mình làm là SSH vào server, gõ loạn xạ top -H, jstat hay jstack để bắt bệnh. Cảm giác giống như đang sửa xe trong bóng tối mà không có đèn pin, cực kỳ thụ động và mệt mỏi.
Sau khi triển khai bộ ba Prometheus JMX Exporter, Prometheus và Grafana, mọi thứ đã khác. Thay vì chờ app sập, mình chỉ cần nhìn Dashboard là biết ngay sự cố sắp xảy ra. Bài viết này đúc kết kinh nghiệm thực tế giúp bạn xây dựng hệ thống giám sát chuẩn chỉnh cho Java App.
JMX Exporter: “Phiên dịch viên” cho JVM
Mọi máy ảo Java (JVM) đều có sẵn JMX để quản lý tài nguyên. Tuy nhiên, Prometheus không thể đọc trực tiếp dữ liệu này vì lệch định dạng. JMX Exporter đóng vai trò một javaagent, chạy song song với ứng dụng để chuyển đổi metrics sang dạng HTTP/text mà Prometheus hiểu được.
Tại sao lại chọn agent thay vì chạy một service riêng? Qua nhiều dự án, mình thấy agent ổn định hơn hẳn. Nó khởi động cùng app, không tốn công quản lý thêm process bên ngoài và giảm thiểu độ trễ khi lấy dữ liệu.
Các bước triển khai thực tế
Bước 1: Tải JMX Exporter Agent
Bạn cần file JAR của agent để nhúng vào app. Hãy tải phiên bản mới nhất (ví dụ 0.20.0) từ Maven Central hoặc GitHub. File này khá nhẹ, chỉ khoảng vài MB.
mkdir -p /opt/monitoring
cd /opt/monitoring
wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.20.0/jmx_prometheus_javaagent-0.20.0.jar
Bước 2: Cấu hình config.yaml thông minh
Nếu không lọc metrics, JMX sẽ đẩy ra hàng nghìn thông số thừa làm nặng Prometheus. Dưới đây là bộ lọc mình hay dùng để tập trung vào những chỉ số quan trọng nhất như CPU, Threads và GC:
# /opt/monitoring/config.yaml
startDelaySeconds: 0
ssl: false
lowercaseOutputName: true
rules:
- pattern: 'java.lang<type=OperatingSystem><>((?!processCpuTime)\w+):'
name: os_$1
type: GAUGE
- pattern: 'java.lang<type=Threading><>ThreadCount:'
name: jvm_threads_current
type: GAUGE
- pattern: 'java.lang<type=Memory><>HeapMemoryUsage:(.*):'
name: jvm_memory_heap_$1
type: GAUGE
- pattern: 'java.lang<type=GarbageCollector, name=(.*)><>CollectionCount:'
name: jvm_gc_collection_count
labels:
gc: "$1"
type: COUNTER
Bước 3: Gắn Agent vào ứng dụng
Bạn chỉ cần thêm một dòng tham số -javaagent vào lệnh khởi chạy. Lưu ý chọn cổng (ví dụ 8080) không trùng với cổng chính của Web App.
java -javaagent:/opt/monitoring/jmx_prometheus_javaagent-0.20.0.jar=8080:/opt/monitoring/config.yaml \
-jar your-app.jar
Sau khi chạy, hãy truy cập http://<IP-Server>:8080/metrics. Nếu thấy các dòng text dạng jvm_memory_heap_used hiện ra là bạn đã thành công.
Bước 4: Kết nối với Prometheus và Grafana
Trong file prometheus.yml, hãy thêm job để Prometheus định kỳ qua lấy dữ liệu (scrape). Mình thường để scrape_interval khoảng 15s là vừa đủ để theo dõi real-time.
scrape_configs:
- job_name: 'java-microservice'
static_configs:
- targets: ['192.168.1.10:8080']
Cuối cùng, hãy lên Grafana và Import Dashboard ID 8563. Bạn sẽ có ngay một giao diện giám sát chuyên nghiệp mà không mất công tự vẽ chart.
3 chỉ số “sinh tử” cần canh gác cẩn thận
Đừng để bị ngợp bởi quá nhiều biểu đồ. Dựa trên kinh nghiệm xử lý sự cố, bạn chỉ cần tập trung vào 3 khu vực sau:
- Heap Memory Usage: Nếu biểu đồ hình răng cưa nhưng đáy sau cao hơn đáy trước, app chắc chắn bị Memory Leak. Hãy đặt cảnh báo khi Heap vượt 85%.
- GC Stop-The-World: Nếu
jvm_gc_collection_seconds_sumtăng vọt, app sẽ bị treo (freeze). Một đợt GC kéo dài trên 200ms thường làm người dùng cảm thấy ứng dụng bị lag rõ rệt. - Thread Count: Số lượng thread tăng liên tục thường do lỗi deadlock hoặc database connection pool bị nghẽn.
Lời kết
Giám sát không chỉ là để ngắm biểu đồ cho đẹp. Nó giúp bạn chuyển từ thế bị động sang chủ động. Thay vì nói “Em nghĩ là do server chậm”, bạn có thể tự tin khẳng định: “Heap đang đầy ở mức 90% do rò rỉ bộ nhớ tại module X”. Chúc các bạn có những đêm ngon giấc với hệ thống monitoring tin cậy!

