Giám sát microservices với Prometheus và Grafana (kèm cảnh báo Slack)

Trong bài viết này, bạn sẽ học cách cấu hình Prometheus và Grafana để theo dõi và gửi cảnh báo lỗi trong hệ thống microservices — đặc biệt là khi service gặp HTTP 5xx lỗi giống như lỗi khi user-service không hoạt động.
1. Tại sao cần giám sát microservices?
Microservices tuy linh hoạt nhưng đi kèm nhiều rủi ro:
Dễ phát sinh lỗi giữa các service mà không ai phát hiện.
Khó xác định nguyên nhân khi hệ thống chậm hoặc lỗi.
Cần một hệ thống cảnh báo tự động để phản ứng kịp thời.
Bộ đôi Prometheus + Grafana giúp bạn:
Thu thập metric từ từng service
Tạo dashboard trực quan
Gửi cảnh báo qua Slack/Email/Telegram
2. Cài đặt Prometheus và Grafana bằng Docker Compose
Tạo file docker-compose.yml
:
services:
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
restart: unless-stopped
grafana:
image: grafana/grafana
ports:
- "3000:3000"
restart: unless-stopped
File prometheus.yml
:
global:
scrape_interval: 10s
scrape_configs:
- job_name: 'user-service'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['host.docker.internal:8081'] # Port của user-service
- job_name: 'order-service'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['host.docker.internal:8082']
- job_name: 'notification-service'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['host.docker.internal:8083']
3. Cấu hình Spring Boot export metric
Trong build.gradle, thêm:
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'io.micrometer:micrometer-registry-prometheus'
Trong application.yml
:
management:
endpoints:
web:
exposure:
include: health,info,prometheus
prometheus:
metrics:
export:
enabled: true
Sau khi khởi động, kiểm tra tại: http://localhost:8082/actuator/prometheus
4. Kết nối Grafana với Prometheus
Truy cập
http://localhost:3000
(tài khoản mặc định:admin/admin
)Add data source:
Prometheus
- URL:
http://prometheus:9090
- URL:
Import dashboard:
JVM (ID:
4701
)Hoặc tạo dashboard riêng cho HTTP request
*Tại sao có dữ liệu dù không gửi request?
Có thể do:
App hoặc framework đang có request nội bộ (health check, actuator...).
Có tool load test hoặc monitoring khác đang quét endpoint.
Trình duyệt của bạn gửi
OPTIONS
,GET /actuator/prometheus
v.v.
Cách kiểm tra:
sum(rate(http_server_requests_seconds_count[1m])) by (method, uri)
→ Xem method + uri nào đang được gọi.
5. Tạo Alert HTTP 5xx và gửi qua Slack
a. Viết Alert Rule:
Truy cập
Alerting → Alert Rules → New Alert Rule
Chọn panel chứa metric
http_server_requests_seconds_count
Query:
sum(rate(http_server_requests_seconds_count{status=~"5..", instance="host.docker.internal:8082"}[1m])) > 0
Condition:
WHEN > 0
Evaluation every 1m, pending 30s
Folder:
HTTP-5xx-Monitoring
Configure notification message
Summary – Viết tiêu đề cảnh báo:
[Order-Service] HTTP 5xx Error Detected
Description – Giải thích chi tiết:
Tỷ lệ lỗi HTTP 5xx trên order-service vượt ngưỡng > 0 trong vòng 1 phút. Hệ thống có thể đang gặp sự cố.
b. Thêm Contact Point Slack
Alerting → Contact Points → Add contact point
Loại: Slack
Nhập Slack Webhook URL (tạo từ Slack Incoming Webhooks)
Bước 1: Tạo Slack App và lấy Webhook
Truy cập: https://api.slack.com/apps
Nhấn Create New App
→ Chọn From scratch
→ Đặt tên App, chọn workspace bạn muốn nhận cảnh báo.Vào mục Incoming Webhooks
→ Bật Activate Incoming Webhooks
→ Nhấn Add New Webhook to WorkspaceChọn kênh bạn muốn gửi cảnh báo (vd:
#alerts
)Copy đường link webhook (có dạng
https://hooks.slack.com/services/XXX/YYY/ZZZ
)
Bước 2: Cấu hình Contact Point trong Grafana
Từ ảnh bạn gửi:
Vào
Alerting → Contact points
Click New contact point
Đặt tên, ví dụ:
Slack-alert-order
Integration: Chọn
Slack
Bỏ trống Token và Recipient → chỉ điền vào Webhook URL (dán webhook đã copy ở Bước 1)
Nhấn Test để kiểm tra gửi tin thử về Slack
Nhấn Save contact point
c. Notification Policy
Alerting → Notification Policies
Set default contact point là Slack
Group by:
grafana_folder
,alertname
Lưu ý: trước khi chạy /actuator/prometheus cần cấu hình lại cho SecurityConfig trong user-service
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
// 👉 CHO PHÉP TRUY CẬP /actuator/prometheus mà không cần token
.requestMatchers("/actuator/prometheus").permitAll()
// 👉 Tùy theo bạn có expose thêm gì nữa
.requestMatchers("/actuator/**").permitAll()
// 👉 Các API khác yêu cầu xác thực (có token Keycloak)
.anyRequest().authenticated()
)
.oauth2ResourceServer(resource -> resource
.jwt(Customizer.withDefaults()) // dùng JWT để xác thực token từ Keycloak
)
.csrf(AbstractHttpConfigurer::disable); // Tắt CSRF cho Prometheus (chỉ GET)
return http.build();
}
6. Mô phỏng lỗi thực tế và nhận cảnh báo
a. Gửi request lỗi:
Tạm tắt user-service
→ Gọi API order:
curl -X POST http://localhost:8082/api/orders \
-H "Authorization: Bearer API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"product": "Macbook Pro",
"price": 2500.0,
"total": 2500.0
}'
b. Slack sẽ nhận tin nhắn sau 30s:
[FIRING:1] Errors HTTP-5xx-Monitoring
Firing
Value: A=0.1638, C=1
summary = [Order-Service] HTTP 5xx Error Detected
A
: là giá trị của biểu thức PromQLC
: số lượng alert đang active
7. Best Practices
Gắn label
application
,instance
,status
vào metricTạo folder riêng theo nhóm cảnh báo
Export dashboard/alert rule ra JSON để version control
Dùng Alertmanager riêng nếu cần gửi SMS/email
8. Giải thích biểu đồ, đơn vị, và cảnh báo
a. ops/s
là gì?
ops/s
viết tắt của operations per second – số lượng request được xử lý mỗi giây. Trong Prometheus, bạn thường thấy các biểu thức rate(metric[1m])
trả về đơn vị này.
Ví dụ:
rate(http_server_requests_seconds_count[1m])
→ Cho biết tốc độ xử lý request mỗi giây trong 1 phút vừa qua.
b. Spike là gì?
Spike là sự tăng vọt đột ngột trong dữ liệu, thường ngắn hạn. Ví dụ spike HTTP 5xx nghĩa là số lượng lỗi tăng vọt trong một thời gian ngắn.
Các spike có thể gây ra false positive, nên alert rule nên dùng thêm
for: 30s
hoặcfor: 1m
để tránh gửi cảnh báo quá sớm.
c. Peak 0.02 ops/s là sao?
Peak = điểm cao nhất. Ví dụ peak 0.02 ops/s nghĩa là tại thời điểm cao nhất, hệ thống xử lý 0.02 lỗi mỗi giây, tức khoảng 1 lỗi mỗi 50 giây.
Tùy vào hệ thống, mức này có thể chấp nhận được nếu không kéo dài. Nếu duy trì cao, cần điều tra root cause.
d. Làm sao biết tham số nào an toàn?
Heap Used < 80%: an toàn. Nếu > 90%, nên kiểm tra leak.
Non-Heap < 70%: bình thường, cao quá có thể do nhiều class load, thread pool, hoặc reflection.
Rate < 10 ops/s: nếu là dev/test thì bình thường. Nếu prod mà thấp thì có thể thiếu traffic hoặc app bị đứng.
Errors = 0: lý tưởng. Nếu > 0 trong thời gian dài → nên alert.
Duration < 100ms (avg): tốt. > 500ms thì bị chậm.
e. So sánh Alertmanager và Alerting của Grafana
Alertmanager là công cụ đi kèm Prometheus, nhận alert từ Prometheus và route đến Slack, Email, Telegram...
Grafana Alerting là hệ thống cảnh báo trực quan, dễ dùng hơn nếu bạn dùng Grafana làm dashboard chính.
Nếu bạn đã dùng Grafana thì KHÔNG bắt buộc dùng Alertmanager. Nhưng nếu muốn kiểm soát luồng alert ở cấp Prometheus (cho nhiều project), nên dùng Alertmanager.
Kết luận
Với Prometheus và Grafana, bạn không chỉ hiển thị được dashboard hệ thống mà còn chủ động cảnh báo ngay khi service gặp sự cố. Bài viết này đã hướng dẫn bạn từ setup đến gửi alert lên Slack — một bước quan trọng trong việc giám sát production.
Bạn có thể mở rộng thêm bằng cách tích hợp Alertmanager, gửi email hoặc kết hợp với các công cụ như Loki/Tempo để truy vết log.
** Các biểu thức PromQL hữu ích\
1. JVM - Memory (Heap / Non-Heap / GC)
1.1 Heap Usage %
(sum(jvm_memory_used_bytes{area="heap"}) / sum(jvm_memory_max_bytes{area="heap"})) * 100
Ý nghĩa: Tính phần trăm bộ nhớ heap đang được sử dụng.
Heap là vùng nhớ chính Java sử dụng để cấp phát object.
Nếu % này cao liên tục mà không giảm => nghi ngờ memory leak hoặc ứng dụng không giải phóng bộ nhớ kịp.
1.2 Non-Heap Usage %
(sum(jvm_memory_used_bytes{area="nonheap"}) / sum(jvm_memory_max_bytes{area="nonheap"})) * 100
Ý nghĩa: Tương tự như trên, nhưng đo cho non-heap memory.
Non-heap chứa metadata, classloader, JIT compiled code.
Nếu % này quá cao => có thể do classloader leak hoặc app load quá nhiều class không cần thiết.
1.3 GC Count
sum(increase(jvm_gc_collection_seconds_count[5m])) by (gc)
Ý nghĩa: Số lần JVM thực hiện Garbage Collection (GC) trong 5 phút qua.
Nếu tăng đột biến => JVM đang cố thu gom rác thường xuyên, có thể do thiếu RAM, leak object...
1.4 GC Time
sum(increase(jvm_gc_collection_seconds_sum[5m])) by (gc)
Ý nghĩa: Tổng thời gian JVM dành cho việc GC trong 5 phút.
GC quá lâu => ảnh hưởng performance (vì GC block thread).
Giúp đánh giá mức độ tốn thời gian của việc thu gom bộ nhớ.
2. CPU
2.1 CPU Usage (process level)
rate(process_cpu_seconds_total[1m])
Ý nghĩa: Tốc độ sử dụng CPU của process JVM (hoặc app khác).
Giúp phát hiện app nào đang "ăn CPU" bất thường.
rate()
dùng để tính tốc độ thay đổi theo thời gian.
2.2 Node-level CPU usage %
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[1m])) * 100)
Ý nghĩa: Phần trăm CPU thực sự đang bận (trừ idle).
Dùng để xem tổng thể máy chủ có đang quá tải không.
3. Thread
3.1 Live Threads
jvm_threads_live_threads
Ý nghĩa: Số lượng thread hiện tại đang chạy (live).
Theo dõi xem ứng dụng có tạo quá nhiều thread bất thường không.
3.2 Daemon Threads
jvm_threads_daemon_threads
Ý nghĩa: Số thread nền (background).
Cao bất thường => có thể đang có task nền bị leak hoặc không được stop.
4. HTTP Metrics
4.1 HTTP Request Count theo status
sum(rate(http_server_requests_seconds_count[1m])) by (status)
Ý nghĩa: Tốc độ request HTTP theo từng status code (200, 500, 404...).
Dễ thấy khi nào bắt đầu có nhiều lỗi hoặc nhiều request bất thường.
4.2 HTTP Error Rate
sum(rate(http_server_requests_seconds_count{status=~"5.."}[1m]))
/
sum(rate(http_server_requests_seconds_count[1m]))
Ý nghĩa: Tỷ lệ lỗi 5xx trong tổng số request HTTP.
Dùng làm alert nếu vượt ngưỡng (ví dụ: > 5% trong 1 phút).
4.3 HTTP Latency - 95 percentile
histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket[5m])) by (le))
Ý nghĩa: 95% request có thời gian xử lý thấp hơn giá trị này.
Giúp theo dõi hiệu năng. Nếu cao => có thể do bottleneck, timeout, hoặc resource quá tải.
5. HikariCP - Connection Pool
5.1 Active Connections
hikaricp_connections_active
Ý nghĩa: Số kết nối DB đang được dùng.
Nếu quá cao liên tục => app có thể không release connection đúng cách.
5.2 Max Connections
hikaricp_connections_max
Ý nghĩa: Giới hạn tối đa connection pool cho DB.
Nếu active gần max => sắp cạn pool => nguy cơ lỗi DB hoặc bottleneck.
5.3 Connection Usage %
(hikaricp_connections_active / hikaricp_connections_max) * 100
Ý nghĩa: Tỷ lệ sử dụng kết nối DB.
Dùng làm chỉ số để scale DB hoặc tune connection pool.
🐳 6. Docker / Container Metrics
6.1 Memory Usage
container_memory_usage_bytes{name=~".+"}
Ý nghĩa: Lượng RAM mỗi container đang tiêu thụ.
Giúp phát hiện container nào "ăn RAM" nhiều nhất.
6.2 CPU Usage
rate(container_cpu_usage_seconds_total{name=~".+"}[1m])
Ý nghĩa: Tốc độ sử dụng CPU của từng container.
Dễ phát hiện container "ngốn tài nguyên".
7. Uptime / Availability
7.1 Uptime
(time() - process_start_time_seconds)
Ý nghĩa: Thời gian ứng dụng đã chạy tính từ lúc start.
Có thể dùng để kiểm tra số lần restart (khi uptime reset về 0).
7.2 Target Up
up{job=~".*"} == 0
Ý nghĩa: Các service target bị Prometheus scrape thất bại (down).
Dùng để cảnh báo khi exporter hoặc app ngừng trả dữ liệu.
Các trường hợp cần đặt alert phổ biến (chia theo nhóm)
1. Availability / Sự sẵn sàng của dịch vụ
Đặt alert khi dịch vụ ngừng hoạt động hoặc không phản hồi đúng:
🔴 HTTP 5xx tăng cao
⛔ Không phản hồi (timeout, connection refused)
⚠️
up == 0
(Prometheus metric cho thấy target không còn scrape được)
Ví dụ PromQL:
up{job="my_service"} == 0
2. Performance / Hiệu năng
Phát hiện sớm khi hệ thống gần quá tải hoặc đang chậm lại:
CPU usage vượt quá 90%
Memory usage vượt 90%
JVM Heap usage > 85% (cảnh báo memory leak)
Request latency > 2s trong 5 phút liên tiếp
Number of threads/connections tăng bất thường
Ví dụ PromQL:
avg_over_time(http_request_duration_seconds_bucket{le="1"}[5m]) > 0.9
3. Error rate / Lỗi ứng dụng
Tăng tần suất lỗi có thể là dấu hiệu hỏng service hoặc bug mới release:
❌ HTTP 500 errors tăng
❌ gRPC code != OK tăng
❌ Spring Boot
exceptions_total
tăng❌ Failed login / authorization tăng
Ví dụ:
sum(rate(http_server_errors_total[1m])) > 5
4. SLA/SLO monitoring
Dùng để đảm bảo cam kết chất lượng dịch vụ, quan trọng khi làm DevOps ở doanh nghiệp:
⚠️ Uptime < 99.9% trong 30 ngày
⚠️ Error rate > 0.1%
⚠️ P99 latency > 1s
Có thể tính theo recording rule rồi alert nếu giá trị vượt ngưỡng.
5. Resource saturation / Cạn kiệt tài nguyên
Bạn cần phát hiện sớm trước khi crash:
Heap gần đầy → tránh OutOfMemoryError
Garbage Collection quá thường xuyên
Disk usage > 90%
Network bandwidth dùng 100%
Số thread/connections quá cao
6. Infrastructure / Hệ thống
Tình trạng phần cứng hoặc container, VM:
🐳 Docker container restarted quá nhiều
Node exporter không gửi metrics
Prometheus bị
high ingestion lag
hoặc bịout of disk
Scrape duration > timeout
7. Custom business alert
Tùy vào hệ thống của bạn:
Đơn hàng thất bại > 10 trong 1 phút
Số user active tụt bất thường
Job không chạy đúng cron
Tổng kết
Loại | Mục tiêu | Alert Ví dụ |
Availability | Sớm phát hiện service die | up == 0 |
Performance | Hiệu năng xuống | CPU > 90% |
Error | Bug xuất hiện | HTTP 5xx > 10 |
SLA | Giữ cam kết | Latency > P95 |
Resource | Phòng tránh sập | Heap > 85% |
Infra | Giám sát nền | Prometheus scrape failed |
Business | Mục tiêu hệ thống | Failed checkout > 5 |
Subscribe to my newsletter
Read articles from Holy_Dev directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Holy_Dev
Holy_Dev
strong desire for learning new things