Metric · Observability

What is resource utilization, and how do you measure it in Metabase?

Resource utilization is used capacity divided by requested or provisioned capacity — how much of the CPU, memory, or nodes you pay for actually does work. It's the bridge between reliability and cost: too high means no headroom for spikes, too low means money spent on idle capacity. Measure it in Metabase from daily snapshots synced from Kubernetes, Amazon ECS, Amazon EKS, or GKE.

TL;DRused ÷ requested per workload per day, from snapshots (not raw metrics streams). Judge against explicit capacity targets — utilization is a trade-off dial, not a score to maximize.

What resource utilization measures

It measures the gap between what workloads claim and what they use. The used-vs-requested view finds over-provisioned deployments (right-sizing candidates); requested-vs-allocatable finds stranded node capacity. Joined with cost allocations, it ranks the gaps by dollars — which is what turns a chart into a backlog.

What data does it need?

  • resource_snapshots: workload, cluster/namespace, snapshot date, requested and used CPU/memory.
  • Optional cost_allocations per service/namespace per day to price the waste.
  • Source: kube-state-metrics + Prometheus, CloudWatch Container Insights, or the Cloud Monitoring API — exported as daily aggregates.

SQL patterns

Utilization vs. requests by workload (14 days)PostgreSQL
SELECT
  workload_name,
  namespace,
  ROUND(AVG(cpu_used_cores / NULLIF(cpu_requested_cores, 0)) * 100, 1)
    AS avg_cpu_utilization_pct,
  ROUND(AVG(memory_used_bytes / NULLIF(memory_requested_bytes, 0)) * 100, 1)
    AS avg_memory_utilization_pct
FROM resource_snapshots
WHERE snapshot_date >= CURRENT_DATE - INTERVAL '14 days'
GROUP BY workload_name, namespace
ORDER BY avg_cpu_utilization_pct ASC;
Utilization and spend by namespacePostgreSQL
SELECT
  s.namespace,
  ROUND(AVG(s.cpu_used_cores / NULLIF(s.cpu_requested_cores, 0)) * 100, 1)
    AS avg_cpu_utilization_pct,
  ROUND(SUM(c.cost_usd), 2) AS cost_usd_30d
FROM resource_snapshots s
JOIN cost_allocations c
  ON c.namespace = s.namespace
  AND c.usage_date = s.snapshot_date
WHERE s.snapshot_date >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY s.namespace
ORDER BY cost_usd_30d DESC;

Pitfalls

Treating high utilization as a win.→ A node at 95% has no room for a spike or a failover. Set target bands per workload class — and treat both tails as findings.
Averaging away the peaks.→ A workload averaging 30% may peak at 100% daily. Keep peak (or p95) utilization next to the average before right-sizing anything.
Confusing used, requested, and allocatable.→ Used ÷ requested finds greedy requests; requested ÷ allocatable finds stranded nodes. Name the denominator on every card.
Right-sizing without the owner.→ Requests encode fear of OOM kills. Pair the over-provisioned table with service owners and change it through them, not around them.

Where this metric applies

Metrics

Dashboards

FAQ

What's a healthy utilization target?
It depends on the workload: latency-sensitive services need headroom — often 40–60% at peak — batch jobs can run hot, and anything with slow autoscaling needs more slack. Set bands per workload class rather than one number, and treat both tails as findings: too high risks availability during spikes, too low is money idling. The infrastructure cost dashboard is where those bands turn into a right-sizing backlog.
Why snapshots instead of live metrics?
Right-sizing and capacity planning are trend questions, not triage. Daily aggregates per workload — resource_snapshots with requested and used CPU and memory — are cheap to store, fast to query, and enough to rank the gaps. The raw streams stay in Prometheus or CloudWatch where they belong; Metabase gets the rollups, the same pattern every observability integration uses. Keep peak or p95 in the snapshot alongside the average so bursty workloads don't look idle.
How do I put a dollar figure on low utilization?
Join resource_snapshots to cost_allocations per namespace or service per day — AWS CUR with split cost allocation for EKS, GCP billing export with cost allocation for GKE, or OpenCost on any Kubernetes cluster. Ranking namespaces by spend next to their average utilization turns "we're over-provisioned" into a prioritized list; the infrastructure cost dashboard shows the pattern.
How do you calculate resource utilization?
Divide used capacity by requested (or provisioned) capacity: cpu_used_cores ÷ cpu_requested_cores per workload per day, and the same for memory. Name the denominator on every card — used over requested finds greedy resource requests, requested over allocatable finds stranded node capacity, and the two point at different fixes. Compute it from daily snapshots built on kube-state-metrics plus Prometheus, CloudWatch Container Insights for ECS, or the Cloud Monitoring API for GKE.
How do you track resource utilization in Metabase?
Sync daily resource_snapshots — workload, namespace, requested and used CPU and memory — from Kubernetes, Amazon EKS, or GKE into a SQL database. Chart average and peak utilization per workload, sort ascending to surface right-sizing candidates, and join cost allocations to rank the gaps by dollars on an infrastructure cost dashboard.