0
0
Lập trình
Sơn Tùng Lê
Sơn Tùng Lê103931498422911686980

Xây Dựng Metrics HTTP Tùy Chỉnh trong Spring Boot

Đăng vào 18 giờ trước

• 6 phút đọc

Xây Dựng Metrics HTTP Tùy Chỉnh trong Spring Boot: Khám Phá Sự Quan Sát

Giới thiệu

Trong thế giới phát triển API hiện đại, các ứng dụng thường phục vụ nhiều loại khách hàng khác nhau, bao gồm ứng dụng di động, dịch vụ đối tác và công cụ nội bộ. Việc theo dõi ai đang gọi API của bạn và tần suất gọi là rất quan trọng cho:

  • Lập kế hoạch năng lực: mở rộng quy mô trước khi lưu lượng truy cập đạt đỉnh.
  • Sử dụng hợp lý và thanh toán: phát hiện những người tiêu dùng có khối lượng lớn.
  • Cảnh báo và SLO: thông báo khi các khách hàng cụ thể gặp sự cố.

Bài viết này sẽ hướng dẫn bạn xây dựng một bộ lọc không phụ thuộc, theo dõi số lượng yêu cầu theo phương thức HTTP và tiêu đề của người tiêu dùng, đồng thời xuất các metric này thông qua Micrometer.

Kiến Trúc Tổng Quan

plaintext Copy
┌──────────┐      ┌────────────────────┐      ┌────────────┐
│  Client  │ ───▶ │Custom MetricsFilter│ ───▶ │ Controller │
└──────────┘      └────────────────────┘      └────────────┘
                      │
                      ▼
               Micrometer Registry
                      │
                      ▼
         Prometheus / Datadog / CloudWatch …

Giải pháp của chúng tôi sử dụng bộ lọc servlet Spring Boot để chặn mọi yêu cầu HTTP và ghi lại các metric bằng Micrometer.

Quy trình như sau:

  • Yêu cầu vào → Bộ lọc → Controller
  • Bộ lọc → Micrometer Counter với thẻ cho phương thức và người tiêu dùng.
  • Metric được lấy hoặc đẩy đến backend quan sát của bạn.

Bước 1: Thêm Micrometer

Spring Boot 3+ bao gồm Micrometer mặc định khi bạn sử dụng spring-boot-starter-actuator. Để sử dụng với Prometheus, thêm phụ thuộc sau vào file pom.xml:

xml Copy
<dependency>
  <groupId>io.micrometer</groupId>
  <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

Tiếp theo, hãy bật các endpoint:

properties Copy
management.endpoints.web.exposure.include=health,metrics,prometheus

Bước 2: Mã Bộ Lọc

Dưới đây là mã cho bộ lọc của chúng ta:

java Copy
@Component
@Order(1)
public class CustomHttpMetricsFilter extends OncePerRequestFilter {

    private static final ConcurrentHashMap<String, Counter> COUNTERS = new ConcurrentHashMap<>();
    private static final String METRIC = "http_requests";

    @Autowired
    private MeterRegistry registry;

    @Override
    protected void doFilterInternal(HttpServletRequest req,
                                    HttpServletResponse res,
                                    FilterChain chain)
            throws ServletException, IOException {

        incrementCounter(req);
        chain.doFilter(req, res);
    }

    private void incrementCounter(HttpServletRequest req) {
        String consumer = req.getHeader("CONSUMER.ID");
        if (consumer == null) consumer = "null";

        String key = req.getMethod() + ":" + consumer;

        COUNTERS.compute(key, (k, existing) -> {
            Counter c = existing;
            if (c == null) {
                c = Counter.builder(METRIC)
                           .tag("method", req.getMethod())
                           .tag("consumer", consumer)
                           .description("Số lượng yêu cầu HTTP theo từng người tiêu dùng")
                           .register(registry);
            }
            c.increment();
            return c;
        });
    }
}

Những Điểm Chính

  • OncePerRequestFilter đảm bảo chỉ thực hiện một lần cho mỗi yêu cầu HTTP.
  • ConcurrentHashMap và phương thức compute tạo ra bộ nhớ cache an toàn cho nhiều luồng của các đối tượng Counter.
  • Các thẻ phương thức và người tiêu dùng giúp mỗi bộ đếm trở nên duy nhất và có thể truy vấn.

Bước 3: Quan Sát Các Metrics

Chạy ứng dụng và thực hiện một vài yêu cầu GET/POST:

bash Copy
curl -H "CONSUMER.ID: mobile-app" http://localhost:8080/api/...

Sau đó, truy cập vào:

plaintext Copy
http://localhost:8080/actuator/prometheus

Bạn sẽ thấy kết quả như sau:

plaintext Copy
http_requests_total{method="GET", consumer="mobile-app"} 42.0
http_requests_total{method="POST", consumer="partner-service"} 5.0

Tại Sao Không Sử Dụng @Timed?

Micrometer cung cấp @Timed cho các phương thức controller, nhưng điều này chỉ hoạt động cho từng endpoint và không tự động nhóm theo tiêu đề tùy chỉnh. Bộ lọc của chúng tôi cung cấp:

  • Phạm vi bao phủ chéo: mọi yêu cầu, ngay cả cho tài nguyên tĩnh hoặc trang lỗi.
  • Thẻ động: bất kỳ tiêu đề hoặc thuộc tính nào có thể trở thành nhãn.

Một Số Mẹo và Cải Tiến Sản Xuất

  • Độ Đặc Trưng Nhãn: Quá nhiều ID người tiêu dùng duy nhất có thể dẫn đến thời gian chuỗi lớn. Giải pháp: giới hạn ID vào một tập hợp đã biết hoặc băm/ẩn danh chúng.
  • Dọn Dẹp Metrics: Cần thiết vì các đối tượng counter không tự thu nhỏ. Giải pháp: triển khai TTL hoặc chỉ đăng ký cho những người tiêu dùng đã biết.
  • Độ Trễ & Mã Trạng Thái: Để đo thời gian yêu cầu và thẻ cho trạng thái HTTP, thêm một bộ đếm thời gian.
  • Bảo Mật: Chỉ nên tiết lộ /actuator/prometheus cho bộ thu thập metrics của bạn.
  • Kiểm Tra: Sử dụng MockMvc và khẳng định.

Kết Luận

Với chưa đến 50 dòng mã, bạn có thể có được cái nhìn thời gian thực về lưu lượng truy cập theo từng người tiêu dùng. Dù bạn đang gỡ lỗi một đợt tăng đột biến hay chuẩn bị cho một buổi ra mắt sản phẩm, những metrics này trở nên vô giá.

“Bạn không thể cải thiện những gì bạn không đo lường.”
Bắt đầu đo lường ngay hôm nay—tương lai của bạn sẽ cảm ơn bạn vì điều đó.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào