Bài 10: Giám sát hiệu năng và đo đạc thời gian với AOP

hoangkimhoangkim
4 min read

Mục tiêu bài học

  • Tạo một Performance Aspect dùng @Around Advice để đo thời gian thực thi method.

  • Tích hợp metric thu thập được vào các công cụ giám sát (Prometheus, Grafana, Datadog, New Relic, v.v.).

  • Biết tối ưu hoá tránh overhead quá cao, phân tích log/metrics một cách có chủ đích.

  • Thực hành một ví dụ case study đo thời gian method quan trọng, đưa ra cảnh báo khi vượt ngưỡng.


Nội dung chính


1. Performance Aspect

  1. Khái niệm:

    • Trong một ứng dụng lớn, các method quan trọng (đặc biệt là “truy cập DB”, “gọi service ngoài”, “tính toán nặng”) cần đo thời gian để biết performance thực tế.

    • Thay vì thủ công chèn System.currentTimeMillis() đầu-cuối mọi nơi, ta viết 1 aspect chung quét tất cả method / method được “đánh dấu”.

  2. Dùng @Around Advice:

    • Advice “bao” toàn bộ lời gọi method, cho phép đo start = System.currentTimeMillis()pjp.proceed()end = ….

    • Ghi log hoặc gửi metric (vd: methodX_time = 50ms) vào Hệ thống giám sát.

  3. Annotation @PerformanceMonitor (gợi ý):

    • Tương tự @Loggable, ta tạo annotation để đánh dấu method nào cần theo dõi:

        @Retention(RetentionPolicy.RUNTIME)
        @Target(ElementType.METHOD)
        public @interface PerformanceMonitor {
            // Có thể thêm tham số threshold, v.v.
        }
      
    • Aspect bắt @PerformanceMonitor => Tự động đo thời gian.


2. Tích hợp Prometheus, Grafana

  1. Micrometer:

    • Là thư viện “thu thập metric” chuẩn trong Spring Boot.

    • Tạo Timer, Counter, Gauge… và publish sang nhiều backend (Prometheus, New Relic, Datadog...).

  2. Prometheus:

    • Thường khởi chạy 1 “endpoint” /actuator/prometheus để Prometheus “scrape” metric.
  3. Grafana:

    • Dùng dashboard theo dõi metric, vẽ biểu đồ.
  4. Cách áp dụng:

    • Mỗi khi method gắn @PerformanceMonitor chạy, aspect:

      • Tạo/ghi Timer (Micrometer) → timer.record(end - start, TimeUnit.MILLISECONDS).

      • Kết quả hiển thị trong Grafana: “Trung bình method X = 40ms”.

  5. Ví dụ:

     @Aspect
     @Component
     public class PerformanceAspect {
    
         private final MeterRegistry meterRegistry;
    
         @Autowired
         public PerformanceAspect(MeterRegistry meterRegistry) {
             this.meterRegistry = meterRegistry;
         }
    
         @Pointcut("@annotation(com.example.monitor.PerformanceMonitor)")
         private void monitorMethods() {}
    
         @Around("monitorMethods()")
         public Object recordExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
             long start = System.currentTimeMillis();
             Object result = pjp.proceed();
             long end = System.currentTimeMillis();
    
             long duration = end - start;
    
             // Tên method: pjp.getSignature().toShortString() 
             String methodName = pjp.getSignature().getName();
    
             // Ghi metric
             Timer timer = Timer.builder("method.performance")
                 .tag("method", methodName)
                 .register(meterRegistry);
             timer.record(duration, TimeUnit.MILLISECONDS);
    
             return result;
         }
     }
    

3. Ví dụ code

  1. Annotation @PerformanceMonitor:

     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.METHOD)
     public @interface PerformanceMonitor {
         // Optional: threshold, description...
     }
    
  2. Service:

     @Service
     public class PaymentService {
    
         @PerformanceMonitor
         public void processPayment(Order order) {
             // Giả lập xử lý payment, tốn thời gian
             // ...
         }
     }
    
  3. Aspect (đã trình bày ở trên).

  4. Kết quả:

    • Gọi paymentService.processPayment(...) → AOP aspect đo thời gian → Ghi metric “method.performance{method=processPayment} = 52ms”.

4. Tối ưu hoá

  1. Không “monitor” toàn bộ method:

    • Chỉ method cốt lõi (ví dụ Payment, Checkout, Calculation...).

    • Lạm dụng => overhead log/metrics, “rác” data.

  2. Sampling:

    • Ở scale lớn, đôi khi ta chỉ theo dõi X% request.

    • Hoặc “monitor theo batch” thay vì method-level.

  3. Kiểm soát log level:

    • Print debug info => overhead, disk usage.

5. Performance Monitoring Troubleshooting

  1. Overhead:

    • Mỗi method log/metrics => tốn CPU + network.

    • Cần giám sát overhead vs. lợi ích.

  2. Sai pointcut:

    • Monitor “quá rộng” => dính cả method trivial => spam metric.
  3. Phân tích:

    • Dữ liệu metric “method X tốn 60ms” => Tìm code optimize? Kiểm tra DB query?
  4. Kiểm soát threshold:

    • Setting alarm? “Nếu processPayment > 100ms → Gửi alert Slack.”

6. Case study

  • Dự án Ecommerce:

    1. Method checkoutService.checkout() → Tính tổng, trừ stock, gọi payment.

    2. @PerformanceMonitorPerformanceAspect ghi time = 120ms.

    3. Prometheus + Grafana → Chart hiển thị “Trung bình 5 phút = 110ms, p95 = 200ms.”

    4. Cảnh báo: Mức threshold 300ms => Quá => Thông báo dev.

Nhờ AOP, ta cắm logic “đo thời gian” 1 lần, apply khắp service. Code business gọn.


Tóm tắt

  • Dùng @Around advice để đo thời gian method, log/ghi metric.

  • Kết hợp Micrometer + Prometheus/Grafana (hoặc New Relic, Datadog) để theo dõi biểu đồ.

  • Cần chọn lọc method quan trọng để monitor, tránh overhead.

  • Bài 11: Tìm hiểu cách AOP hỗ trợ logging/tracing/security tại kiến trúc microservices.


Câu hỏi thảo luận

  1. Những method nào không nên bị “tracking” quá nhiều? Có tiêu chí lựa chọn method cốt lõi nào?

  2. Bạn từng dùng New Relic/Datadog thay vì Prometheus? So sánh ưu/nhược?

0
Subscribe to my newsletter

Read articles from hoangkim directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

hoangkim
hoangkim