Skip to content

Heap e limit

Query che non richiedono exporter JVM: funzionano su qualsiasi workload Java del cluster. Unica variabile: $NS. Vedi come si usano.

Prima query da lanciare. Sopra l’85% stabile il GC gira in continuo.

100 * container_memory_working_set_bytes{namespace="$NS",container!="",container!="POD"}
/ on(namespace,pod,container) group_left
kube_pod_container_resource_limits{resource="memory",namespace="$NS"}
topk(10,
100 * container_memory_working_set_bytes{namespace="$NS",container!="",container!="POD"}
/ on(namespace,pod,container) group_left
kube_pod_container_resource_limits{resource="memory",namespace="$NS"}
)
100 * container_memory_working_set_bytes{namespace="$NS",pod=~"nome-app-.*",container!="",container!="POD"}
/ on(namespace,pod,container) group_left
kube_pod_container_resource_limits{resource="memory",namespace="$NS"}
100 * sum(container_memory_working_set_bytes{namespace="$NS",container!="",container!="POD"})
/ sum(kube_pod_container_resource_limits{resource="memory",namespace="$NS"})

Per capire se il problema è isolato o diffuso.

topk(15,
100 * sum by (namespace) (container_memory_working_set_bytes{container!="",container!="POD",namespace!~"kube-.*|openshift-.*"})
/ sum by (namespace) (kube_pod_container_resource_limits{resource="memory",namespace!~"kube-.*|openshift-.*"})
)
sum by (pod, container) (container_memory_working_set_bytes{namespace="$NS",container!="",container!="POD"}) / 1024^3

Delta ampio significa molta page cache contabilizzata nel limit: il margine reale è più stretto di quanto sembri.

sum by (pod, container) (container_memory_rss{namespace="$NS",container!="",container!="POD"})
/ sum by (pod, container) (container_memory_working_set_bytes{namespace="$NS",container!="",container!="POD"})

Causa sottovalutata di pause GC lunghe: i thread del collector non ottengono quota CFS. Sopra il 25% è patologico per un workload Java.

100 * sum by (pod, container) (rate(container_cpu_cfs_throttled_periods_total{namespace="$NS",container!="",container!="POD"}[5m]))
/ sum by (pod, container) (rate(container_cpu_cfs_periods_total{namespace="$NS",container!="",container!="POD"}[5m]))
topk(10,
100 * sum by (pod, container) (rate(container_cpu_cfs_throttled_periods_total{namespace="$NS",container!="",container!="POD"}[5m]))
/ sum by (pod, container) (rate(container_cpu_cfs_periods_total{namespace="$NS",container!="",container!="POD"}[5m]))
)
100 * sum by (pod, container) (rate(container_cpu_cfs_throttled_periods_total{namespace="$NS",pod=~"nome-app-.*",container!=""}[5m]))
/ sum by (pod, container) (rate(container_cpu_cfs_periods_total{namespace="$NS",pod=~"nome-app-.*",container!=""}[5m]))
topk(10,
100 * sum by (namespace,pod,container) (rate(container_cpu_cfs_throttled_periods_total{container!="",container!="POD",namespace!~"kube-.*|openshift-.*"}[5m]))
/ sum by (namespace,pod,container) (rate(container_cpu_cfs_periods_total{container!="",container!="POD",namespace!~"kube-.*|openshift-.*"}[5m]))
)
sum by (pod, container) (rate(container_cpu_usage_seconds_total{namespace="$NS",container!="",container!="POD"}[5m]))
/ on(namespace,pod,container) group_left
kube_pod_container_resource_limits{resource="cpu",namespace="$NS"}

Sotto 2 core il collector parallelo degrada sensibilmente.

sum by (pod, container) (container_spec_cpu_quota{namespace="$NS",container!="",container!="POD"})
/ sum by (pod, container) (container_spec_cpu_period{namespace="$NS",container!="",container!="POD"})

Distinguere i due casi cambia il rimedio: alzare il limit su un leak sposta il problema di qualche ora.

Se resta stabilmente > 0 è un leak.

deriv(container_memory_working_set_bytes{namespace="$NS",container!="",container!="POD"}[6h])
topk(10,
deriv(container_memory_working_set_bytes{namespace="$NS",container!="",container!="POD"}[6h]) * 3600 / 1024^2
)
deriv(container_memory_working_set_bytes{namespace="$NS",pod=~"nome-app-.*",container!=""}[6h]) * 3600 / 1024^2

Base per il rightsizing, da confrontare col limit attuale. Vedi anche Capacity per namespace.

max_over_time(container_memory_working_set_bytes{namespace="$NS",container!="",container!="POD"}[7d:5m]) / 1024^3

Se il minimo settimanale cresce insieme al massimo la old gen non viene liberata: leak confermato.

min_over_time(container_memory_working_set_bytes{namespace="$NS",container!="",container!="POD"}[7d:5m]) / 1024^3

Risultato negativo o assente = nessuna crescita, quindi undersizing e non leak.

(
kube_pod_container_resource_limits{resource="memory",namespace="$NS"}
- on(namespace,pod,container)
container_memory_working_set_bytes{namespace="$NS",container!="",container!="POD"}
)
/ on(namespace,pod,container)
deriv(container_memory_working_set_bytes{namespace="$NS",container!="",container!="POD"}[6h])
/ 3600
predict_linear(container_memory_working_set_bytes{namespace="$NS",container!="",container!="POD"}[6h], 4*3600) / 1024^3

Da confrontare con -Xmx: il rapporto non dovrebbe superare 0.75.

kube_pod_container_resource_limits{namespace="$NS",resource="memory"} / 1024^3

Senza limit la JVM vede tutta la RAM host e dimensiona l’heap di conseguenza: candidati a far esplodere il nodo.

count by (namespace,pod,container) (container_memory_working_set_bytes{namespace="$NS",container!="",container!="POD"})
unless on(namespace,pod,container)
kube_pod_container_resource_limits{resource="memory"}
count by (namespace,pod,container) (container_memory_working_set_bytes{container!="",container!="POD",namespace!~"kube-.*|openshift-.*"})
unless on(namespace,pod,container)
kube_pod_container_resource_limits{resource="memory"}

Per OOMKill, restart e correlazione con terminated reason vedi Restart / CrashLoop / OOM.

In un pod con sidecar Istio il raggruppamento by (pod, container) li separa già. Per le metriche di mesh vedi Multi-container.

sum by (pod, container) (container_memory_working_set_bytes{namespace="$NS",container!="",container!="POD",container!="istio-proxy"}) / 1024^3
sum by (pod) (container_memory_working_set_bytes{namespace="$NS",container="istio-proxy"}) / 1024^3
sum by (pod) (container_memory_working_set_bytes{namespace="$NS",container="istio-proxy"})
/ sum by (pod) (container_memory_working_set_bytes{namespace="$NS",container!="",container!="POD",container!="istio-proxy"})