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

Holy_DevHoly_Dev
12 min read

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
  • 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

    1. Truy cập: https://api.slack.com/apps

    2. 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.

    3. Vào mục Incoming Webhooks
      → Bật Activate Incoming Webhooks
      → Nhấn Add New Webhook to Workspace

    4. Chọn kênh bạn muốn gửi cảnh báo (vd: #alerts)

    5. 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:

  1. Vào Alerting → Contact points

  2. Click New contact point

  3. Đặt tên, ví dụ: Slack-alert-order

  4. Integration: Chọn Slack

  5. Bỏ trống Token và Recipient → chỉ điền vào Webhook URL (dán webhook đã copy ở Bước 1)

  6. Nhấn Test để kiểm tra gửi tin thử về Slack

  7. 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 PromQL

  • C: số lượng alert đang active


7. Best Practices

  • Gắn label application, instance, status vào metric

  • Tạ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ặc for: 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ạiMục tiêuAlert Ví dụ
AvailabilitySớm phát hiện service dieup == 0
PerformanceHiệu năng xuốngCPU > 90%
ErrorBug xuất hiệnHTTP 5xx > 10
SLAGiữ cam kếtLatency > P95
ResourcePhòng tránh sậpHeap > 85%
InfraGiám sát nềnPrometheus scrape failed
BusinessMục tiêu hệ thốngFailed checkout > 5
0
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