Modernizing Prometheus: Native Storage for Composite Types

Bài tóm tắt Prometheus 2026 4. Điều chỉnh Độ khó: Khó

Prometheus · 2026 · 4. Điều chỉnh · Độ khó: Khó — bài gốc

Bài của một maintainer (Bartłomiej Płotka), tự nói là góc nhìn cá nhân; vài thay đổi chưa được team chính thức duyệt hoặc chưa kiểm chứng ở production.

Bối cảnh

  • TSDB của Prometheus từ đầu chỉ lưu mẫu nguyên thuỷ: label dạng chuỗi, giá trị float64, timestamp int64, không biết loại metric. Loại metric là quy ước bên trên: counter có hậu tố _total, info có _info.
  • Loại phức hợp (histogram, summary, gaugehistogram, stateset) được biểu diễn bằng một nhóm series: histogram cổ điển là các counter foo_bucket{le=...} + foo_count + foo_sum.
  • Mô hình này giúp Prometheus là một trong những TSDB mã nguồn mở tối ưu nhất, và là nền của Cortex, Thanos, Mimir. Nhưng có bốn giới hạn:
    • Hiệu quả: mỗi bucket là một series mới tốn chỗ trong index, trong khi mẫu thì nén tốt.
    • Chức năng: khó lưu dữ liệu có hình phức tạp.
    • Tính giao dịch: các phần của một histogram đi riêng; qua remote write hay OTLP có thể mất hay trễ một bucket và gây cảnh báo sai.
    • Độ tin cậy: bên đọc phải đoán ngữ nghĩa; không gì cấm ghi một gauge tên foo_bucket.

Diễn tiến

  • Native histogram đưa vào TSDB mẫu phức hợp đầu tiên (bucket thưa, hàm mũ, lưu nguyên tử). Lúc đó ý kiến chung là dừng ở đó, chờ người dùng tự chuyển, nhưng chuyển cần sửa PromQL, bucket, client, và phần mềm cũ có thể không bao giờ chuyển, nên mô hình cổ điển sẽ phải giữ hàng chục năm.
  • 2024: NHCB (native histogram với custom bucket) lưu histogram cổ điển dạng phức hợp, theo bài hiệu quả hơn ít nhất 30% với tính năng tương đương. Hai vướng mắc: gộp từ dạng cổ điển sang NHCB lúc scrape tốn kém, và gần như không làm được với dữ liệu đẩy tới (các bucket có thể đi qua các shard remote write khác nhau); cách đọc đổi (histogram_quantile(0.9, sum(foo)) thay cho sum(foo_bucket) by (le)), phá quy tắc "thấy gì query nấy" và ảnh hưởng federation, remote read, remote write.
  • Hướng đi (2026): về lâu dài toàn bộ tầng lưu trữ dùng mẫu phức hợp, nhưng người dùng chuyển được phần lưu trữ (ví dụ bật lúc scrape) mà không làm hỏng phía đọc, để bỏ được mô hình cổ điển sớm:
    1. Bàn thêm native summary và stateset.
    2. OpenMetrics 2.0: giá trị phức hợp ngay trong định dạng text, giải bài toán gộp; mặc định vẫn trải ra dạng cổ điển lúc scrape nên chưa phá gì.
    3. Remote Write 2.0 chở histogram dạng native (vẫn hỗ trợ dạng cũ).
    4. Chế độ tương thích khi đọc: dịch mẫu phức hợp ngược ra dạng cổ điển, để query cũ foo_bucket ... by (le) vẫn chạy trên NHCB; tính cả cho remote write, federation, remote read.
  • Cái giá: kích thước mẫu thôi đồng đều mà phụ thuộc loại, đổi đặc tính hiệu năng; code nhiều loại mẫu dài dòng (tác giả muốn Go có union).

Bài học cho SWE

  • Một mô hình dữ liệu tối giản giúp hệ đi xa, nhưng thứ bị đẩy lên quy ước đặt tên (kiểu, tính nguyên tử) sẽ thành nợ khi dữ liệu đi qua nhiều hệ (Observability và monitoring).
  • Đổi định dạng lưu trữ mà không đợi mọi bên đọc chuyển: lớp dịch ngược khi đọc cho phép tách thời điểm đổi bên ghi khỏi thời điểm đổi bên đọc (Migration không downtime).
  • Chuyển đổi một chiều dễ (trải ra), chiều kia khó (gộp lại); đặt điểm chuyển đổi ở chỗ còn đủ thông tin, tức là ở nguồn hoặc trong giao thức.

Liên quan