Tổng kết — Observability & Production-ready
Cheat sheet Actuator, probe, loại meter, percentile và tracing OTLP, kèm self-assessment năm năng lực observability của module.
TL;DR: Module này bóc sáu khái niệm: bề mặt Actuator, health indicator và hai loại probe, bốn loại meter Micrometer, percentile P99, Observation API, và tracing OTLP. Đây là một trang để bookmark — cheat sheet tra nhanh, glossary, pitfall tổng hợp, và checklist tự đánh giá cho cả module.
Đã đi qua những gì
Module bắt đầu từ một câu hỏi rất cụ thể: TaskFlow đang chạy, nhưng nó có "khoẻ" không, ai trả lời được câu đó? Actuator mở bề mặt để hỏi được ứng dụng đang chạy; health indicator biến câu trả lời thành hai probe Kubernetes tách biệt — readiness và liveness, nhầm giữa hai cái tạo ra restart loop thay vì giải quyết sự cố. Micrometer đo số lượng bằng đúng loại meter cho từng câu hỏi, và cardinality của tag hoá ra là chỗ tốn tiền nhất nếu không cẩn thận. Percentile đọc đúng con số Timer đã ghi, thay vì để trung bình cộng giấu đi phần đuôi tệ nhất. Observation API gộp việc đo metric và mở trace vào một điểm khai báo, và tracing OTLP đi bước cuối: theo dấu một request cụ thể xuyên nhiều service, nối thẳng vào dòng log JSON. Mini-challenge TaskFlow v5 khép vòng bằng cách gắn cả sáu mảnh đó vào một hệ thống thật.
flowchart LR
M["Metric<br/>Micrometer + Percentile"] -- "bao CO van de" --> Q{"Dashboard bao dong"}
Q --> T["Trace<br/>Observation API + OTLP"]
T -- "chi ra O DAU" --> R["Span cham nhat trong request"]🗺️ Cheat sheet
| Concept | Khi nào dùng | Pitfall |
|---|---|---|
management.endpoints.web.exposure.include | Mọi production — whitelist tường minh, không "*" | Copy nguyên config dev sang production, lộ env/heapdump |
management.server.port | Tách hẳn Actuator khỏi cổng công khai | Tưởng tách cổng là đủ, bỏ luôn SecurityFilterChain |
| Readiness probe | Dependency ngoài (DB, service khác) chậm hoặc mất kết nối tạm thời | Gộp dependency ngoài vào liveness — restart không sửa được gì |
| Liveness probe | Tiến trình tự kẹt cứng (deadlock, heap không giải phóng) | Trỏ vào endpoint kiểm tra DB — tạo restart loop |
Counter | Đếm sự kiện đã xảy ra bao nhiêu lần, chỉ tăng | Dùng đếm đại lượng cần giảm (số đang xử lý) |
Gauge | Giá trị ngay lúc đo, lên xuống tự do | Đo trên snapshot cục bộ — mất strong reference, gauge lặng lẽ biến mất |
Timer | Vừa đếm vừa ghi thời lượng | Dùng Gauge đo thời lượng — mất hết phân bố |
DistributionSummary | Phân bố một đại lượng không phải thời gian | Dùng Counter cộng dồn — mất hình dạng phân bố |
Tag hữu hạn (priority, status) | Mọi metric tag | Gắn userId/orderId/URL thô — cardinality nổ theo tích |
percentiles (client-side) | Một instance, không cần gộp | Tưởng gộp được qua nhiều pod — percentile không cộng được |
percentiles-histogram | Nhiều instance, cần P99 đúng nghĩa hệ thống | Bật tràn lan trên metric cardinality đã cao — nhân thêm một chiều bucket |
| SLO + error budget | Biến percentile thành cam kết đo được | Thiếu cửa sổ thời gian — SLO vô nghĩa |
lowCardinalityKeyValue / highCardinalityKeyValue | Tag lên cả metric+span / chỉ lên span | Gắn nhầm ID vào low-cardinality — enforce bằng chữ ký method, không phải kỷ luật |
traceparent (W3C Trace Context) | Mang trace ID xuyên network, mọi ngôn ngữ | Tự new HTTP client builder — bỏ qua auto-config, trace đứt |
| Sampling probability | Head-based, mù trước lỗi | Đặt quá thấp — đúng request lỗi cần điều tra bị bỏ sót |
📖 Glossary module
| Thuật ngữ | Định nghĩa 1 câu | Nguồn |
|---|---|---|
| Actuator | Tập endpoint quản trị Spring Boot trả lời câu hỏi vận hành (sức khoẻ, cấu hình, số đo) | Bài 01 |
| Management port | Cổng riêng phục vụ Actuator, tách khỏi cổng ứng dụng công khai | Bài 01 |
| Readiness probe | Kubernetes hỏi "ngay lúc này pod nhận request được không" | Bài 02 |
| Liveness probe | Kubernetes hỏi "tiến trình còn cứu được không, hay phải giết đi tạo lại" | Bài 02 |
| Health indicator | Component tự viết, kiểm tra một dependency cụ thể rồi báo UP/DOWN | Bài 02 |
| Micrometer | Facade đo lường trung lập vendor, cùng ý tưởng với SLF4J cho logging | Bài 03 |
| Meter | Tên chung cho Counter/Gauge/Timer/DistributionSummary | Bài 03 |
| Cardinality | Số chuỗi thời gian (time series) một metric tạo ra, tính bằng tích số giá trị các tag | Bài 03 |
| Percentile | Ngưỡng mà đúng P% giá trị trong tập số đo nằm dưới hoặc bằng nó | Bài 04 |
| Error budget | Phần trăm còn lại của SLO, tính ra một con số request cụ thể được phép vượt ngưỡng | Bài 04 |
| Observation | Một lần khai báo "có việc đáng quan sát", các handler tự dựng Timer/Span từ đó | Bài 05 |
ObservationRegistry | Registry trung tâm phát lifecycle event cho các ObservationHandler đã đăng ký | Bài 05 |
| Trace | Toàn bộ hành trình xử lý một request, xuyên qua mọi service nó đi qua | Bài 06 |
| Span | Một chặng có tên trong hành trình đó, gắn span ID riêng và tham chiếu span cha | Bài 06 |
| OTLP | OpenTelemetry Protocol — giao thức chuẩn hoá cách gửi span, metric và log tới collector | Bài 06 |
| Context propagation | Cơ chế mang trace context xuyên qua network, giữa các service khác ngôn ngữ | Bài 06 |
| Tail-based sampling | Collector giữ toàn bộ span một trace tới khi kết thúc mới quyết định giữ hay bỏ | Bài 06 |
⚠️ Pitfall tổng hợp
❌ include: "*" copy từ dev sang production → ✅ whitelist tường minh, "*" chỉ đặt trong profile dev riêng.
❌ Health indicator của một dependency downstream gán vào liveness → ✅ mọi dependency ngoài thuộc readiness; liveness chỉ giữ livenessState mặc định.
❌ readiness.include liệt kê indicator mới mà quên readinessState → ✅ include thay thế toàn bộ danh sách mặc định, luôn giữ readinessState là phần tử đầu.
❌ Đếm "số đang xử lý" bằng Counter → ✅ dùng Gauge đọc giá trị sống, Counter chỉ dành cho đại lượng chỉ tăng.
❌ Gắn tag userId/orderId vào metric để "lọc theo user cho tiện" → ✅ ID định danh một entity thuộc về log và trace, không thuộc metric.
❌ Đọc P99 hệ thống bằng cách lấy trung bình cộng P99 của từng instance → ✅ bật percentiles-histogram, để backend gộp bucket rồi mới tính bằng histogram_quantile().
❌ Health indicator tự viết không set timeout, thừa hưởng timeout mặc định của client bên dưới → ✅ luôn set timeout ngắn tường minh, ngắn hơn nhiều lần chu kỳ probe.
❌ Tự new RestClient.Builder() thay vì inject RestClient.Builder đã auto-config → ✅ constructor injection, chỉ builder auto-config mới tự chèn traceparent.
✅ Self-assessment
- Design bề mặt Actuator cho production: expose endpoint nào, chặn endpoint nào, vì sao tách cổng quản trị
- Nếu chưa: đọc lại bài 01, mục "Tách cổng quản trị — biện pháp mạnh nhất"
- Implement health indicator riêng và map đúng vào readiness so với liveness probe
- Nếu chưa: đọc lại bài 02, mục "Viết HealthIndicator riêng cho dependency downstream"
- Implement metric Micrometer đúng loại meter và kiểm soát cardinality của tag
- Nếu chưa: đọc lại bài 03, mục "Vì sao hoá đơn monitoring phình ra?"
- Diagnose độ trễ bằng percentile P99 và explain vì sao trung bình cộng che mất sự cố
- Nếu chưa: đọc lại bài 04, mục "Vì sao trung bình cộng nói dối với độ trễ?"
- Trace một request xuyên nhiều service bằng Observation API và OTLP, nối trace ID vào log
- Nếu chưa: đọc lại bài 05 mục "Một Observation, nhiều handler cùng nghe" và bài 06 mục "Nối trace ID vào log"
Liên hệ các module khác
- Module 01 — Modern Java trong Spring —
RestClient/@HttpExchangedựng ở đó chính là chỗtraceparentđược tự động chèn ở bài 06; sealedResultmap lỗi nghiệp vụ cũng là ứng viên tốt cho tagoutcomelow-cardinality ở bài 03 và 05. - Module 03 — Caching, Async & Scheduling — cache,
@Async,@Scheduledđều là chỗ tiếp theo cần observability: cache hit/miss là mộtCountertự nhiên, và context propagation khi đẩy việc sang thread khác (bài 06 đã cảnh báo) là chủ đề trọng tâm của module đó.
🚀 What's next
Module tiếp theo là Caching, Async & Scheduling — ba annotation cùng đi qua một cơ chế AOP proxy: @Cacheable, @Async, @Scheduled. Bạn dùng lại nguyên bộ quan sát vừa dựng ở module này để trả lời câu hỏi mới: cache đang hit hay miss bao nhiêu phần trăm, task async có bị nuốt exception không, job scheduled có chạy trùng khi nhiều instance không — tất cả đều cần metric và trace để trả lời, chứ không đoán được bằng mắt.
📚 Tài liệu mở rộng
- Sách: Observability Engineering (Charity Majors, Liz Fong-Jones, George Miranda — O'Reilly) — phân biệt monitoring và observability, lý do metric/log/trace không thay thế nhau.
- Spec / paper: W3C Trace Context — chuẩn
traceparent; Google SRE Workbook — Implementing SLOs — error budget trong thực hành vận hành. - Reference chính thức: Spring Boot Actuator Reference — mọi property nhắc tới suốt module; Micrometer Reference — Concepts, Observation, Tracing.
- Video/Talk: tìm bằng từ khoá "Micrometer Observation API" hoặc "OpenTelemetry Java tracing" trên kênh hội nghị Spring — kiểm ngày phát hành trước khi xem, vì Observation API còn đổi nhanh giữa các bản Boot.
Bài này đáng gửi cho bạn học cùng?
Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.
Bài này có giúp bạn hiểu bản chất không?
Hỏi đáp về bài này
Chưa có câu hỏi
Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).
Đặt câu hỏi đầu tiên