Chi Phí Ingestion & Mô Hình Billing Active Time Series
Đơn vị billing thật sự là gì: sample, không phải time series
Sai lầm phổ biến nhất khi ước tính chi phí GMP là nghĩ theo đơn vị "số lượng metric" hoặc "số lượng time series" như một con số tĩnh. Theo tài liệu chính thức, "số lượng sample được ingest là yếu tố đóng góp chính vào chi phí" và "Managed Service for Prometheus tính phí trên cơ sở mỗi sample" (Cost controls and attribution). Một time series không tự nó tốn tiền — nó tốn tiền mỗi lần một sample mới của nó được ghi, tức mỗi lần scrape thành công. Đây là khác biệt về bản chất quan trọng vì nó tạo ra công thức chi phí có hai biến độc lập nhân với nhau, không phải một biến duy nhất:
Chi phí ingest ∝ (số time series) × (tần suất ghi mỗi time series)
= cardinality × (1 / scrape interval)Hệ quả trực tiếp: giảm scrape interval đi một nửa giảm chi phí đi một nửa, bất kể cardinality; và giảm cardinality đi một nửa cũng giảm chi phí đi một nửa, bất kể scrape interval. Hai đòn bẩy này độc lập với nhau và cả hai đều tuyến tính — không có đòn bẩy nào "quan trọng hơn" một cách tuyệt đối, mức độ ưu tiên phụ thuộc vào việc metric nào đang có giá trị nào cao bất thường.
Công thức thực tế từ dữ liệu chính thức: 900 sample/giây cho một cluster ba node "mặc định"
Tài liệu blog kỹ thuật chính thức đưa ra một con số tham chiếu cụ thể rất hữu ích để hiệu chỉnh trực giác: một cluster GKE ba node với cấu hình kube-prometheus mặc định (không lọc gì) tạo ra khoảng 900 sample mỗi giây, chỉ riêng từ các exporter hệ thống chuẩn (kube-state-metrics, node-exporter, cAdvisor, kube-apiserver metrics) (Controlling metric flow in Managed Service for Prometheus). Đây là con số đáng chú ý vì nó phát sinh trước khi bất kỳ ứng dụng nghiệp vụ nào của bạn export một metric nào — tức là chi phí nền tảng (baseline cost) của việc chỉ đơn giản bật GMP trên một cluster.
Từ baseline này, tài liệu đưa ra hai đòn bẩy giảm cụ thể với hệ số đã đo:
Đòn bẩy 1 — điều chỉnh scrape interval, tác động toàn cục:
| Interval | Giảm volume so với 10s |
|---|---|
| 10s → 30s | ~66% |
| 10s → 60s | ~83% |
Khuyến nghị chính thức: đặt baseline 30 giây cho hầu hết metric, chỉ dùng 60 giây khi có lý do rõ ràng (metric ít biến động, không cần alert real-time), và chỉ giữ interval ngắn (10-15s) cho các metric RED thực sự cần độ nhạy cao (request rate, error rate, latency của service tier quan trọng).
Đòn bẩy 2 — content filtering, tác động chọn lọc: dùng metricRelabeling với action keep, ví dụ chỉ giữ metric kube_* liên quan đến workload, giảm được khoảng 125 sample/giây trên baseline 900. Tắt hẳn một service monitor không cần thiết (ví dụ kube-apiserver nếu không có nhu cầu giám sát control plane chi tiết) giảm thêm khoảng 200 sample/giây.
Điểm mấu chốt cần rút ra: hai đòn bẩy này nên áp dụng theo thứ tự khác nhau tùy bài toán. Nếu vấn đề là quá nhiều metric không dùng đến (nhiều metric key khác nhau, mỗi cái cardinality thấp), content filtering hiệu quả hơn. Nếu vấn đề là một số ít metric có cardinality rất cao (nhiều label value), giảm scrape interval cho riêng nhóm metric đó (qua PodMonitoring riêng biệt với interval khác) hiệu quả hơn giảm toàn cục.
Read request: chi phí thứ hai, thường bị bỏ qua
Ngoài sample ingest, GMP còn tính phí cho read request đến Monitoring API — mỗi lần một PromQL query, một dashboard load, hoặc một rule evaluation chạy, đó là một read request. Chi phí này thường nhỏ hơn nhiều so với ingest cost trong hầu hết trường hợp, nhưng có thể tăng đột biến trong hai tình huống dễ bị bỏ qua: (1) dashboard tự động refresh với interval quá ngắn trên nhiều panel PromQL phức tạp cùng lúc; (2) recording rule/alerting rule evaluate quá thường xuyên trên biểu thức tốn kém (đã nói ở file 03 và sẽ khai triển thêm ở file 06). Rule evaluation tự nó cũng là read request — một rule group với interval: 15s chạy 4 lần mỗi phút, 5760 lần mỗi ngày, nhân với số rule trong group.
Metrics Management: công cụ cost attribution chính thức
Thay vì đoán, GCP cung cấp trang Metrics Management trong Cloud Console như công cụ điều tra chi phí chính thức. Theo tài liệu, trang này báo cáo:
- Ingestion volume theo cả byte và sample, breakdown theo metric domain (Prometheus/custom/GKE system...)
- Label cardinality của từng metric — cho biết chính xác metric nào có cardinality cao bất thường
- Read count — metric nào được query nhiều nhất, hữu ích để biết metric nào "đáng" giữ độ chi tiết cao
- Usage trong alerting/dashboard — cho biết metric nào đang thực sự được dùng, để tránh xóa nhầm metric quan trọng khi cắt giảm
- Write error rate — tỷ lệ ghi lỗi, một tín hiệu gián tiếp cho thấy vấn đề cấu hình
Resource cụ thể để attribute chi phí theo chiều tổ chức (namespace, workload, region, project) là metric Metric Ingestion Attribution với field Samples written by attribution id — cho phép query PromQL kiểu:
sum(rate(monitoring_googleapis_com:billing_samples_ingested[1h])) by (namespace)để trả lời câu hỏi thực tế nhất trong vận hành cost: "namespace nào đang chiếm phần lớn chi phí ingest tháng này?" — câu hỏi mà nếu không có cơ chế attribution này sẽ không thể trả lời chỉ bằng cách nhìn hóa đơn tổng.
Ví dụ tính toán thực tế: từ baseline đến sau tối ưu
Để công thức cardinality × (1 / scrape interval) không chỉ là lý thuyết, hãy áp dụng vào một trường hợp cụ thể mà nhiều đội platform gặp phải: một cluster GKE 20 node, chạy kube-prometheus mặc định cộng thêm khoảng 30 microservice tự expose metric qua client library HTTP framework chuẩn (mỗi service trung bình 40 metric distinct, mỗi metric trung bình 15 time series do label như method, status_code, path_template).
Bước 1 — Ước lượng baseline: theo hệ số tham chiếu chính thức, một cluster ba node mặc định tạo khoảng 900 sample/giây chỉ từ exporter hệ thống. Với 20 node (thay vì 3), phần lớn metric hệ thống (node-exporter, cAdvisor) tỷ lệ tuyến tính theo số node, nên baseline hệ thống ước tính khoảng 900 × (20/3) ≈ 6.000 sample/giây. Cộng thêm ứng dụng: 30 service × 40 metric × 15 series = 18.000 time series, với scrape interval mặc định 15 giây tương đương 18.000 / 15 = 1.200 sample/giây. Tổng baseline: khoảng 7.200 sample/giây.
Bước 2 — Áp dụng đòn bẩy interval: chuyển toàn bộ metric ứng dụng từ 15 giây lên 30 giây (mức giảm ~50% cho riêng phần này, tương ứng hệ số quan sát được khi tăng gấp đôi interval). Phần ứng dụng giảm còn khoảng 600 sample/giây. Phần hệ thống giữ nguyên nếu không đổi (thường an toàn để giữ 15-30s cho node-exporter vì cardinality thấp, chi phí giảm không đáng kể).
Bước 3 — Áp dụng content filtering: rà soát 40 metric mỗi service, phát hiện khoảng 15 trong số đó là metric debug/nội bộ không dùng cho dashboard hay alert nào (xác nhận qua Metrics Management, cột "read count" bằng 0). Áp dụng metricRelabeling allowlist loại bỏ 15 metric này, giảm thêm khoảng 37.5% phần ứng dụng còn lại: 600 × 0.625 ≈ 375 sample/giây.
Kết quả: từ baseline ~7.200 sample/giây xuống còn khoảng 6.000 (hệ thống, không đổi) + 375 (ứng dụng, đã tối ưu) ≈ 6.375 sample/giây — một mức giảm khiêm tốn ở ví dụ này vì phần lớn tải đến từ metric hệ thống, không phải ứng dụng. Bài học quan trọng rút ra từ chính ví dụ số này: trước khi tối ưu, luôn xác định phần lớn sample đến từ đâu (hệ thống hay ứng dụng) bằng Metrics Management — tối ưu sai phần (ví dụ chỉ tập trung vào 30 microservice trong khi 6.000/7.200 sample đến từ tầng hệ thống) sẽ cho hiệu quả rất thấp so với công sức bỏ ra.
Vì sao "xóa metric không dùng" không rẻ như tưởng tượng
Một hành động cost-cutting trực giác là xóa metric descriptor không còn dùng đến. Nhưng cần hiểu rõ hệ quả: xóa metric descriptor xóa vĩnh viễn toàn bộ lịch sử dữ liệu của metric đó — không có cách khôi phục. Vì vậy, hành động đúng đắn theo thứ tự ưu tiên nên là:
- Ngăn sample mới được ghi (qua
metricRelabelingactiondroptại PodMonitoring) — dừng chi phí phát sinh thêm ngay lập tức, không ảnh hưởng dữ liệu lịch sử. - Chờ dữ liệu cũ tự hết hạn theo chính sách retention (xem file 07) — vì retention của GMP có cơ chế downsample tự động, chi phí lưu trữ dữ liệu cũ giảm dần theo thời gian mà không cần hành động chủ động.
- Chỉ xóa descriptor tường minh khi đang giải quyết vấn đề quota (25.000 descriptor mỗi project đã nói ở file 04), không phải như một thao tác "dọn dẹp" thường xuyên.
Bài học thiết kế: cost review nên là một phần của code review, không phải một audit riêng biệt
Hệ quả thực tiễn quan trọng nhất rút ra từ mô hình billing này: vì chi phí tỷ lệ trực tiếp và tức thời với cách một exporter được cấu hình (scrape interval, label nào được export, metricRelabeling nào được áp dụng), quyết định cost thực chất được đưa ra tại thời điểm viết PodMonitoring YAML, không phải tại thời điểm nhận hóa đơn cuối tháng. Một tổ chức trưởng thành về vận hành GMP nên coi việc thêm một PodMonitoring mới hoặc thêm một label vào metric hiện có là một thay đổi cần review giống như review một thay đổi schema database — vì hệ quả cardinality của nó thường không thể nhìn thấy ngay (chỉ lộ ra sau vài tuần khi label value tích lũy đủ nhiều), giống hệt như một migration schema tệ chỉ gây vấn đề khi dữ liệu đủ lớn.