Skip to main content
Version: Next (unreleased)

Performance

KubeAtlas serves its read API from a graph store that comes in two tiers — Tier 1 (in-memory) and Tier 2 (PostgreSQL + Apache AGE). Both are benchmarked against synthetic stress fixtures so a release can be checked for regressions.

Latency targets​

The cluster and namespace views and the blast-radius walk are the hot read paths. The v1.2 service-level targets, p95:

EndpointTarget (p95)
cluster-view (/graph?level=cluster)≤ 1000 ms
namespace-view (/graph?level=namespace)≤ 1000 ms
blast-radius≤ 500 ms

These were briefly relaxed to 5–8 s during the v1.0 work, while every cluster/namespace view materialised the whole graph in the API process per request. The store-side pushdown aggregation moved that work into the store (a GROUP BY on Tier 2, a single pass on Tier 1), so v1.2 reclaims the original targets.

Baselines​

Captured with test/perf/bench-v1.sh (100 samples per endpoint) on Docker Desktop Kubernetes under WSL2. Tier 2 numbers include kubectl port-forward + WSL2 round-trip overhead; Tier 1 is a local memory-backed process. p95, milliseconds:

Endpoint5K T15K T210K T110K T2
cluster-view7.6145.029.1360.2
namespace-view36.9696.1390.81433.9 ⚠
blast-radius0.75.90.79.3
  • 5K — the stress-test-5k fixture (~7.2K resources), the v1.0 / v1.1 baseline (perf-baseline-v1.0.json, perf-baseline-v1.1.json).
  • 10K — the stress-test-10k fixture (~14.4K resources), the v1.2 baseline (perf-baseline-v1.2.json).
  • Multi-cluster (v1.3) — two-cluster federation fixture captured by test/perf/start-multicluster-fixture.sh. The /api/v1/federation/graph?level=cluster path returns in 6 ms p50 (vs. 2177 ms for the resource-level merge) — a 200× reduction from the store-side cluster-summary aggregator added in v1.3.0. Numbers in perf-baseline-v1.3.json.

cluster-view and blast-radius stay well inside target on both tiers at both scales. blast-radius is near-flat because a recursive-CTE traversal is bounded by the affected subgraph, not the total graph.

⚠ The one over-target cell — 10K Tier 2 namespace-view (1.43 s). This is a known artefact of the synthetic fixture, not a product regression. stress-test-10k puts all ~10K resources in a single namespace; on Tier 2 the NamespaceSubgraph JOIN then costs more than a full scan, because the namespace filter selects 100 % of the rows. Real namespaces are a small slice of a cluster, where the JOIN is a clear win — and the realistic whole-graph aggregation, cluster-view, lands at 360 ms p95. Tier 1 (in-memory) is unaffected. The synthetic single-namespace fixture is deliberately not optimised for; see perf-baseline-v1.2.json for the recorded numbers.

Regression gate​

test/verify/perf-regression.sh re-runs the benchmark and fails CI if any metric, on any tier, against either the v1.0 or the v1.2 baseline, regresses by more than 20 %:

# capture a fresh run per fixture, then:
bash test/verify/perf-regression.sh

v1.6.0 validation scope and benchmark targets​

The published v1.6.0 release used one-hour functional validation and a separate short public-install smoke check. It does not claim dedicated performance acceptance or endurance. See the release matrix for the exact source, artifacts, evidence, and limits.

The historical baselines above and the original benchmark protocol below are retained as regression tools, not final-release acceptance results. A future performance claim requires all three measurements on the exact tested commit:

Evidence rowKubernetes fixtureResourcesNamespace p95
Default 5KOne synthetic namespace: 5,000 ConfigMaps, 1,000 Deployments, and 200 ServicesChart-default requests and limits; the 75% runtime boundary derives a 384MiB Go soft limitGated at 1 second
Production 10KThe same deterministic shape distributed over 10 namespacesv160-production-10k-values.yaml; the same 75% boundary derives 1536MiB from 2GiGated at 1 second
Pathological 10KAll 10K fixture objects in one namespaceThe same production profileRecorded, but not substituted for the representative gate

All three rows gate cluster-view p95 at 1 second and blast-radius p95 at 500 milliseconds. Each endpoint receives at least 100 samples, and any HTTP failure fails the row even when it would fall below the p95 rank. Evidence also records the clean Git commit, immutable application and PostgreSQL image IDs, rendered resource settings and Go memory limit, exact fixture counts, Kubernetes and container-runtime versions, host capacity, RSS, restarts, and OOM state.

The reusable benchmark tools and resource profiles are present on main; that is not a claim that final-release performance validation passed. Keep workstation-specific orchestration and run evidence outside the source tree. Retain all three measurements with their inputs, failures, and artifact identities so another reviewer can independently assess the results.