Capacity Planning
This guide helps you size a Mockarty installation before it goes live: how much
CPU and memory each component needs, how many PostgreSQL connections to
provision, and which settings to change as you grow. The numbers below are the
product’s real defaults, not estimates.
For how the components fit together, see Scaling Architecture.
Starting sizes
| Component | Minimum | Recommended for production | Notes |
|---|---|---|---|
| Admin node | 2 vCPU / 2 GB | 4 vCPU / 4 GB | The web UI, the API, schedulers and mock serving. Memory, not CPU, is what runs out first. |
| PostgreSQL | 1 GB RAM | 2 GB RAM, SSD disk | Size the disk from your data retention, not from the number of users. |
| Redis | 512 MB | 1 GB | Optional on a single node, required for several admin nodes. |
| Mock resolver | 1 vCPU / 512 MB | 1 vCPU / 1 GB | Add resolvers to serve more mock traffic. |
| Runner | depends on the work | — | Load tests and browser tests need the most; size each runner for the tests it runs. |
A desktop or evaluation install needs only the admin node: it can keep its data
in a local SQLite file and its cache in memory.
Helm chart defaults
The Helm chart ships requests and limits that let every pod start on a small
cluster. Treat them as a floor: for production, set the admin node’s CPU and
memory to at least the recommended size above.
| Component (values key) | Requests (CPU / memory) | Limits (CPU / memory) |
|---|---|---|
Admin node (admin) |
200m / 256Mi | 1000m / 2Gi |
Mock resolver (resolver) |
100m / 128Mi | 500m / 512Mi |
Runner (runner) |
100m / 128Mi | 500m / 512Mi |
PostgreSQL (postgresql.primary) |
100m / 256Mi | 500m / 512Mi |
Redis (redis.master) |
50m / 64Mi | 200m / 256Mi |
Change them in your values file, for example:
admin:
resources:
requests: { cpu: "1", memory: 2Gi }
limits: { cpu: "4", memory: 4Gi }
PostgreSQL connections
Running out of database connections is the most common capacity problem in a
multi-node installation: requests start failing even though CPU and memory are
fine. Plan the connection count before you scale.
Each admin node keeps two connection pools and a few dedicated connections for
live updates:
| Setting | Default | What it sizes |
|---|---|---|
DB_MAX_OPEN_CONNS |
25 | Main pool: mock matching, reading and saving data |
BOOTSTRAP_DB_MAX_OPEN_CONNS |
4 per CPU, between 16 and 30 | Service pool: licences, schedulers, notifications, runners |
| Live-update connections | up to 10 | Cluster events and live screen updates; not configurable |
| Mock resolver pool | 3 | Each resolver’s read-only connections |
“CPU” is the CPU limit of the admin container (or of the machine, when there is
no limit). So one admin node uses at most:
per admin node = DB_MAX_OPEN_CONNS + BOOTSTRAP_DB_MAX_OPEN_CONNS + 10
Count every pod that can exist at the same time — the autoscaling maximum plus
the extra pod a rolling update starts — and keep the total at or below 80 % of
PostgreSQL’s max_connections. The rest is for backups, migrations and your own
sessions:
total = (admin pods + surge) × per admin node + (resolver pods + surge) × 3
How the chart’s own profiles add up:
| Profile | Admin pods | Resolver pods | Worst case | max_connections |
|---|---|---|---|---|
Default (values.yaml) |
2 × (25 + 16 + 10) | 0 | 102 | 200 |
Cluster (values.cluster.yaml) |
5 × (15 + 16 + 10) | 11 × 3 | 238 | 300 |
The chart raises max_connections of its bundled PostgreSQL for exactly this
reason: PostgreSQL’s own default of 100 is too small even for one admin node
during a rolling update. With an external PostgreSQL, apply the formula to your
shape and either raise max_connections or lower the pools:
admin:
env:
DB_MAX_OPEN_CONNS: "15"
BOOTSTRAP_DB_MAX_OPEN_CONNS: "16"
postgresql:
primary:
extendedConfiguration: |
max_connections = 300
Every PostgreSQL connection costs server memory, so raise PostgreSQL’s memory
together with max_connections. With many resolvers, a connection pooler in
front of PostgreSQL keeps the count low.
SQLite (desktop and single binary)
A node that stores its data in SQLite opens its main pool at 2 connections per
CPU (between 4 and 32, SQLITE_MAX_OPEN_CONNS overrides it) and a service pool
of 1 per CPU (between 4 and 8). Reads run in parallel; writes take turns. SQLite
suits one person or a small team on one machine — move to PostgreSQL before
several people write at the same time.
Redis
Each admin node opens up to 10 Redis connections per CPU, never fewer than 20
(CACHE_REDIS_POOL_SIZE overrides it), and keeps at least 4 of them warm
(CACHE_REDIS_MIN_IDLE_CONNS). If your Redis limits clients, keep
admin pods × pool size below its maxclients.
In-memory cache
Without Redis, each admin node caches in its own memory, up to 200 MB by default
(REPO_INMEMORY_MAX_SIZE_MB). Count it in the admin node’s memory limit.
Disk
Database disk grows with the history you keep — request logs, test run results
and the audit log — not with the number of mocks or users. Set the cleanup
policies in the administration panel to match the retention you need, then plan
disk as daily volume × retention days plus about 30 % headroom. Large report
files and attachments go to the file or object storage, which you size
separately. Scaling Architecture has worked
examples for small, medium and large teams.
When to scale
| What you see | What to do |
|---|---|
| Mock responses slow down under load | Add mock resolvers |
| The admin node’s memory approaches its limit | Raise the admin memory limit, or add admin nodes behind a load balancer |
| Errors mentioning “too many clients” or connection timeouts | Recalculate the PostgreSQL connection budget above |
| Test runs wait in the queue | Add runners with the capabilities those tests need |
| Database disk keeps growing | Shorten the retention in the cleanup policies |