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
┌──────────┐ ┌────────────────────┐ ┌────────────┐
│ 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
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
Tiếp theo, hãy bật các endpoint:
properties
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
@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
curl -H "CONSUMER.ID: mobile-app" http://localhost:8080/api/...
Sau đó, truy cập vào:
plaintext
http://localhost:8080/actuator/prometheus
Bạn sẽ thấy kết quả như sau:
plaintext
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 đó.