Ga naar inhoud

Measuring what your instance can actually carry

The upstream batch stack ships a full monitoring set — Prometheus, Grafana, a node exporter, a Celery exporter and more — and on the reference deployment it retains five years. So the question "how much can this box take" does not need new tooling. It needs the right three queries, and a load event to point them at.

This page is the queries. It assumes the deployment from deploy-instance-vps.md; adjust container names if yours differ.

The three numbers that matter

Available memory is the first wall you hit. Each Celery worker is capped by WORKER_MEMORY_LIMIT (1 GB by default) and the stack runs several, on top of routinator's several hundred megabytes of RPKI data.

Queue depth tells you whether work is piling up or being consumed. If celery_queue_length stays at zero under load, the bottleneck is not a backlog — the workers are keeping up and something else is the limit.

Load average says whether the CPUs are saturated. Read it against your core count: 3.75 on two cores is nearly 2× subscribed.

Running the queries

Prometheus listens inside the compose network, with /prometheus/ as its external path. From the host:

q() {
  docker exec internetnl-prod-prometheus-1 sh -c \
    "wget -qO- \"http://127.0.0.1:9090/prometheus/api/v1/query?query=$1\"" \
    | sed -e 's/.*"value":\[[0-9.]*,"//' -e 's/"\].*//'
}

Current state:

q "node_memory_MemAvailable_bytes/1024/1024"   # MB free
q "sum(celery_queue_length)"                   # total queue depth
q "node_load1"                                 # 1-minute load

Looking back at a window that has already passed — this is the useful one, because you rarely watch a load event live. @ <unix-timestamp> anchors the query to the end of the window you care about:

E=$(date -u -d '2026-09-08 09:10' +%s)         # end of the window
q "min_over_time(node_memory_MemAvailable_bytes[110m]%20@%20${E})/1024/1024"
q "max_over_time(sum(celery_queue_length)[110m:]%20@%20${E})"
q "max_over_time(node_load1[110m]%20@%20${E})"

Note the %20 — the query goes in a URL, so spaces must be encoded. And note the [110m:] with a colon in the queue query: sum(...) produces an instant vector, so it needs a subquery range, not a plain range selector.

Reading the answer honestly

A measurement of your own sequential batch tells you about sequential batches. It does not tell you what happens when two tenants submit at the same moment — for that you need either real concurrent users or a deliberate concurrent test.

Worked example, from the reference deployment on a 2-core, 3.7 GB VPS measuring 362 domains in blocks of 25:

Idle Under load
Available memory ~995 MB 520 MB
Queue depth 0 0
node_load1 ~0.3 3.75

Conclusion drawn from it: memory is the constraint, the workers kept up, and the CPUs were saturated but coping. About half the memory headroom went to a single sequential user — which is a reason to be careful about promising concurrency, not a reason to believe there is 520 MB spare.