Skip to content

Kiến trúc Monarch & GMP ở Quy Mô Toàn Cầu

Tại sao cần hiểu Monarch, không chỉ hiểu GMP

Phần lớn tài liệu về Managed Service for Prometheus (GMP) mô tả nó như "Prometheus nhưng không cần quản lý storage". Điều đó đúng nhưng nguy hiểm nếu dừng lại ở đó, vì nó khiến người vận hành tiếp tục tư duy như đang chạy một Prometheus instance đơn lẻ — chỉ là "lớn hơn và ai đó khác quản lý nó". Thực tế khác hẳn: khi bạn ghi metric vào GMP, dữ liệu đó rời khỏi mọi khái niệm "instance" và đi vào Monarch — hệ thống time series database nội bộ mà Google dùng để vận hành chính hạ tầng của họ, được mô tả trong bài báo VLDB 2020 "Monarch: Google's Planet-Scale In-Memory Time Series Database".

Con số quy mô của Monarch (tính đến thời điểm công bố paper) minh họa rõ sự khác biệt về bản chất: hệ thống lưu trữ gần 950 tỷ time series, dùng khoảng 750 TB bộ nhớ, nhận 2.2 TB dữ liệu ingest mỗi tháng, và phục vụ khoảng 6 triệu query mỗi giây trên toàn cầu. Đây không phải "một Prometheus to hơn" — đây là một hệ thống phân tán multi-tenant mà Prometheus của bạn chỉ là một trong hàng triệu client ghi vào.

Hiểu điều này quan trọng vì gần như mọi giới hạn và failure mode được nói đến trong các phần sau của chương (quota, cardinality limit, query timeout, quarantine) không phải là giới hạn tùy tiện của GMP — chúng là hệ quả tất yếu của việc chia sẻ một hệ thống lưu trữ ở quy mô hành tinh cho hàng triệu tenant khác nhau, mỗi tenant phải bị cô lập khỏi tenant khác về resource usage.

Kiến trúc ba tầng: Root Mixer → Zone Mixer → Leaf

Monarch tổ chức truy vấn toàn cầu theo mô hình cây ba tầng:

                    Root Mixer
                   (toàn cầu, fan-out theo zone)
                /         |          \
        Zone Mixer    Zone Mixer    Zone Mixer
        (us-central1) (europe-west1) (asia-southeast1)
           /   \           /  \           /   \
        Leaf  Leaf      Leaf  Leaf     Leaf  Leaf
      (in-memory, sharded theo key range)

Leaf là nơi dữ liệu thực sự nằm — một in-memory time series store, sharded theo key range một cách lexicographic. Điểm mấu chốt: dữ liệu được lưu tại chính zone (data center) nơi nó được sinh ra. Một Pod chạy tại us-central1 sinh metric thì metric đó nằm vật lý trên leaf tại us-central1, không phải được replicate ngay lập tức đi khắp thế giới.

Zone Mixer nhận truy vấn được route đến zone của nó, fan-out tiếp xuống các leaf trong zone, thực hiện phần lớn công việc tính toán (aggregation, filtering) ở tầng này trước khi trả kết quả lên trên.

Root Mixer nhận query gốc từ client (PromQL query bạn gõ vào Metrics Explorer hoặc Grafana), quyết định những zone nào cần được hỏi dựa trên label selector (đặc biệt là project_id, location, cluster), rồi fan-out xuống các zone mixer tương ứng, cuối cùng gộp kết quả lại.

Vì sao thiết kế fan-out này quan trọng khi bạn viết PromQL

Một chi tiết được nêu rõ trong tài liệu vận hành Monarch: "khi một node nhận query, nó xác định các operation nào có thể chạy ở tầng thấp hơn và chỉ gửi xuống phần việc đó". Nói cách khác, Monarch cố gắng đẩy phép tính (aggregation, rate) xuống càng sâu càng tốt để giảm lượng dữ liệu phải truyền lên tầng trên.

Hệ quả trực tiếp: một query như

promql
sum(rate(http_requests_total[5m])) by (cluster)

được Monarch thực thi hiệu quả vì rate() và bước đầu của sum by (cluster) có thể chạy tại leaf/zone mixer — mỗi zone chỉ cần trả về kết quả đã aggregate theo cluster, không phải toàn bộ raw time series. Nhưng một query như:

promql
topk(10, http_requests_total)

không thể aggregate cục bộ theo cách đó một cách hoàn hảo — topk toàn cục đòi hỏi nhìn thấy toàn bộ tập kết quả trước khi xếp hạng, buộc nhiều dữ liệu hơn phải di chuyển lên root mixer. Đây là lý do vì sao các query dạng "global top-N" hoặc query có nhiều phép nối (join qua vector matching phức tạp) có chi phí cao hơn hẳn so với query aggregate đơn giản theo label — không phải vì PromQL "khó" mà vì cấu trúc fan-out không cho phép đẩy phép tính đó xuống các tầng dưới.

Mental model đúng cần có ở đây: mỗi query PromQL trên GMP là một fan-out request phân tán qua tối thiểu hai tầng mạng (root → zone → leaf), không phải một lần đọc từ local TSDB. Latency và cost của một query phụ thuộc vào (1) bao nhiêu zone bị chạm tới, (2) bao nhiêu leaf trong mỗi zone phải trả lời, và (3) bao nhiêu phần của phép tính có thể được đẩy xuống trước khi kết quả di chuyển lên tầng trên.

Global query scope: hệ quả trực tiếp từ kiến trúc này

Chương 39 đã nói global query scope là lợi thế lớn nhất của GMP so với self-hosted Prometheus. Bây giờ ta có thể giải thích tại sao nó khả thi về mặt kiến trúc: vì root mixer có khả năng fan-out đến bất kỳ zone nào chứa dữ liệu thuộc project_id/metrics scope của bạn, bạn không cần tự dựng Thanos Query hay Cortex để liên kết nhiều Prometheus instance lại — root mixer đã đóng vai trò global query layer đó sẵn, cho toàn bộ Google Cloud, không riêng gì cụm của bạn.

Theo tài liệu chính thức: "By querying Monarch instead of querying data from local Prometheus servers, you get global monitoring at scale" (Query using the Prometheus API or UI). Điều này cũng giải thích tại sao khái niệm metrics scope (một construct chỉ tồn tại ở thời điểm đọc, cho phép gộp nhiều project vào một view truy vấn) hoạt động được — nó chỉ đơn giản là danh sách project được phép truyền vào root mixer làm điều kiện filter khi fan-out.

Managed Collection vs Self-Deployed Collection: khác biệt kiến trúc, không chỉ khác biệt vận hành

Chương 39 mô tả collector DaemonSet như cách "mặc định" để đưa dữ liệu vào GMP. Ở quy mô lớn, bạn cần phân biệt rõ hai chế độ thu thập, vì chúng dẫn đến các quyết định tối ưu khác nhau ở phần sau của chương:

Managed collectiongmp-operator triển khai và quản lý toàn bộ vòng đời của collector DaemonSet. Bạn chỉ tương tác qua PodMonitoring/ClusterPodMonitoring CRD. Google chịu trách nhiệm vận hành binary collector, upgrade, resource sizing mặc định.

Self-deployed collection — Theo tài liệu chính thức, "With self-deployed data collection, you manage your Prometheus installation as you always have. The only difference is that you run the Managed Service for Prometheus drop-in replacement binary" (Get started with self-deployed collection). Bạn tự vận hành một Prometheus server (thường qua prometheus-operator hoặc kube-prometheus), nhưng thay binary Prometheus gốc bằng image gke.gcr.io/prometheus-engine/prometheus:vX.Y.Z-gmp.N-gke.M — binary này vẫn scrape theo config Prometheus chuẩn, nhưng thay vì ghi vào local TSDB, nó export dữ liệu thẳng vào Monarch qua các cờ --export.*.

Sự khác biệt này không phải là chi tiết vận hành phụ — nó quyết định bạn có quyền local aggregation hay không trước khi dữ liệu rời khỏi cluster. Với managed collection, bạn chỉ có metricRelabeling ở tầng scrape (drop/keep theo regex) chứ không có recording rule chạy tại chỗ trước khi export. Với self-deployed collection, bạn có toàn quyền chạy recording rule local để "cuộn" (roll up) cardinality cao thành metric tổng hợp trước khi dữ liệu rời cluster, dùng flag --export.match để lọc theo PromQL selector trước khi export ra Monarch. Đây chính là cơ chế thay thế cho Thanos federation mà file 07 sẽ phân tích sâu.

Chi phí resource của self-deployed: tài liệu khuyến nghị tăng CPU/memory limit lên gấp 5 lần so với Prometheus thông thường khi dùng chế độ self-deployed, vì binary export thêm một tầng xử lý (buffer, batch, gRPC streaming lên Monarch) so với việc chỉ ghi vào local TSDB.

Ranh giới quan sát: bạn không thể "xem" bên trong Monarch

Một hệ quả thực tế quan trọng của kiến trúc managed: bạn không có quyền truy cập trực tiếp vào leaf hay zone mixer để debug tại sao một query chậm. Không có /status/tsdb hay promtool tsdb analyze như Prometheus tự host. Công cụ quan sát duy nhất bạn có là:

  1. Collector UI (chỉ áp dụng cho phần scrape, trước khi dữ liệu vào Monarch) — port-forward tới collector Pod cổng 19090, xem /targets để biết target nào đang được scrape thành công.
  2. Metrics Management page trong Cloud Console — cho thấy volume ingest, cardinality theo metric, nhưng không cho thấy chi tiết shard/leaf nào đang xử lý.
  3. Thông báo lỗi từ chính API response (ví dụ RESOURCE_EXHAUSTED, "Monitored resource has too many time series") — đây thực chất là tín hiệu gián tiếp cho biết Monarch đang áp giới hạn bảo vệ tenant khác khỏi tenant của bạn.

Mental model cần ghi nhớ: khi một query GMP timeout hoặc trả về Cancelled due to number of queries, đó không phải bug — đó là cơ chế bảo vệ multi-tenant của Monarch đang hoạt động đúng như thiết kế. Bạn không "sửa" Monarch; bạn thay đổi cách bạn viết query hoặc cấu trúc metric để giảm tải cho tầng dưới. Đây là khác biệt tư duy cốt lõi so với vận hành Prometheus tự host, nơi bạn có thể tăng resource limit của chính Prometheus Pod để "chịu tải" nhiều hơn.

So sánh nhanh: điều gì thay đổi khi chuyển tư duy từ Prometheus instance sang Monarch tenant

Khái niệm Prometheus tự hostKhái niệm tương đương trên GMP/Monarch
Local TSDB trên disk, retention tự cấu hìnhLeaf in-memory, retention theo chính sách downsample cố định của Google (xem file 07)
Một Prometheus instance = một scope queryRoot mixer fan-out toàn metrics scope, không giới hạn theo cluster
Tự tăng CPU/mem của Prometheus Pod khi tải caoKhông thể — giới hạn nằm ở quota per-project và cơ chế quarantine per-tenant
promtool tsdb analyze để xem cardinality cục bộMetrics Management page, metricDescriptors.list API
Federation để nối nhiều clusterKhông cần — root mixer đã làm việc này cho toàn bộ metrics scope

Những điều cần mang sang các phần sau

Từ kiến trúc ba tầng này, ba hệ quả sẽ được khai triển chi tiết ở các phần tiếp theo của chương:

  1. PodMonitoring và ScrapeLimits (file 02) tồn tại vì đây là điểm kiểm soát duy nhất trước khi dữ liệu rời cluster đi vào Monarch — một khi đã vào Monarch, bạn không còn cách nào "xóa bớt" cardinality mà không phải xóa cả metric descriptor.
  2. Cardinality explosion (file 04) là vấn đề nghiêm trọng chính vì mỗi label value mới tạo ra một time series mới trên leaf — và một leaf/shard chứa quá nhiều time series cho một monitored resource sẽ bị Monarch "quarantine" thay vì âm thầm chấp nhận.
  3. Query cost trong PromQL (file 06) phụ thuộc trực tiếp vào việc phép tính có đẩy được xuống zone mixer/leaf hay không — hiểu điều này giúp bạn viết lại query để tránh timeout thay vì đổ lỗi cho "GMP chậm".

Tham khảo chính thức