Kodeloka
  1. Kodeloka
  2. Kelas Prometheus
  3. Materi

Modul 9 · Modul 9 dari 15

Vector Matching Lanjutan: group_left, Subquery & Info Metric

Menggabungkan metrik dari sumber berbeda, menambahkan metadata ke hasil query, dan teknik query di atas query.

Masalah: Metrik Terpisah, Butuh Digabung

Anda punya http_requests_total{instance} dan ingin menampilkan versi aplikasi yang hanya ada di metrik app_build_info{instance, versi}. Ini pekerjaan untuk vector matching many-to-one.

Pola "Info Metric"

Konvensi umum: buat satu metrik gauge bernilai 1 yang isinya hanya metadata.

/metricstext
app_build_info{versi="2.4.1", commit="a3f21c", instance="10.0.0.5:8080"} 1
kube_pod_labels{pod="api-7d4f", label_tim="checkout", label_tier="backend"} 1
node_uname_info{instance="10.0.0.5:9100", release="6.8.0-51-generic"} 1

group_left — Menempelkan Label

group-leftpromql
# Laju request, DITAMBAH label versi dari app_build_info
sum by (instance) (rate(http_requests_total[5m]))
  * on (instance) group_left(versi)
  app_build_info

# Baca dari kiri ke kanan:
#   * on (instance)        -> cocokkan berdasarkan label instance
#   group_left(versi)      -> sisi KIRI boleh punya banyak series per
#                             satu series di kanan; ambil label 'versi'
#                             dari sisi kanan
ModifierArtinya
group_leftSisi kiri "banyak", sisi kanan "satu". Label diambil dari kanan.
group_rightKebalikannya: sisi kanan "banyak", kiri "satu".
on (a, b)Cocokkan hanya berdasarkan label a dan b.
ignoring (c)Cocokkan berdasarkan semua label kecuali c.
⛔ Error found duplicate series for the match group

Ini error yang paling sering muncul saat memakai join. Artinya: sisi "satu" ternyata punya lebih dari satu series untuk kunci pencocokan yang sama.

Penyebab umum: aplikasi mengekspos dua app_build_info (misalnya setelah deploy versi baru, keduanya sempat ada bersamaan).

Solusi: paksa menjadi satu dengan agregasi:

promql
... * on (instance) group_left(versi)
  max by (instance, versi) (app_build_info)

Contoh Nyata: Menghubungkan Pod ke Tim Pemilik

k8s-joinpromql
# CPU per pod, ditambah label tim dari kube_pod_labels
sum by (pod, namespace) (rate(container_cpu_usage_seconds_total{container!=""}[5m]))
  * on (pod, namespace) group_left(label_tim)
  max by (pod, namespace, label_tim) (kube_pod_labels)

# Lalu bisa diagregasi per tim -> laporan biaya per tim
sum by (label_tim) (
  sum by (pod, namespace) (rate(container_cpu_usage_seconds_total{container!=""}[5m]))
    * on (pod, namespace) group_left(label_tim)
    max by (pod, namespace, label_tim) (kube_pod_labels)
)

Subquery — Query di Atas Query

Menjalankan sebuah ekspresi berulang kali sepanjang rentang waktu, menghasilkan range vector baru.

subquerypromql
# Sintaks: <ekspresi>[rentang_total:langkah]

# Laju request tertinggi dalam 1 jam terakhir,
# dihitung dari rate 5 menit setiap 1 menit
max_over_time( rate(http_requests_total[5m])[1h:1m] )

# Apakah error rate pernah melebihi 5% dalam 6 jam terakhir?
max_over_time(
  (
    sum(rate(http_requests_total{status=~"5.."}[5m]))
    / sum(rate(http_requests_total[5m]))
  )[6h:5m]
) > 0.05

# Berapa lama (detik) CPU berada di atas 90% dalam 24 jam?
sum_over_time( (avg(rate(node_cpu_seconds_total{mode!="idle"}[5m])) > bool 0.9)[24h:1m] ) * 60
⚠️ Subquery itu mahal

[24h:1m] berarti Prometheus menjalankan ekspresi bagian dalam 1.440 kali. Bila ekspresi itu sendiri berat, satu query bisa memakan puluhan detik dan menghabiskan memori.

Jangan pernah menaruh subquery di dalam alerting rule. Ganti dengan recording rule yang menghitung nilai dasarnya secara berkala.

Manipulasi Label

labelpromql
# Ekstrak hostname dari "10.0.0.5:9100" menjadi "10.0.0.5"
label_replace(up, "host", "$1", "instance", "([^:]+):.*")

# Gabungkan beberapa label menjadi satu
label_join(up, "kunci", "/", "job", "instance")

# Menyamakan nama label agar dua metrik dari sumber berbeda bisa di-join
label_replace(metrik_a, "instance", "$1", "node", "(.*)")