Docker Idle CPU and Memory Baseline
February 13, 2026 ยท View on GitHub
This document explains why KalamDB can show non-zero CPU and memory while idle in Docker, even with an empty database.
Summary
Observed on February 13, 2026 using jamals86/kalamdb:latest with no user queries:
- Idle CPU: typically
~0.5%to~1.6%(short spikes higher) - Idle memory: typically
~20 MiBto~28 MiBin default Docker single-node setup - Idle thread count: around
29-30threads
This is expected baseline runtime overhead, not active query load.
Why CPU is not 0%
1. Actix worker pool defaults to CPU cores
When workers = 0, Actix uses num_cpus::get().
- Code path:
backend/src/lifecycle.rs - Worker setup:
workers(if config.server.workers == 0 { num_cpus::get() } else { ... })
More workers means more runtime scheduling overhead even when no requests are processed.
2. Standalone mode still uses the Raft code path
KalamDB intentionally uses RaftExecutor in both standalone and cluster modes.
- Code path:
backend/crates/kalamdb-core/src/app_context.rs - Standalone path:
RaftManagerConfig::for_single_node(...)
Single-node Raft still keeps internal ticking/election state active for correctness and shared code paths.
3. Raft group runtime is still active in single-node
In single-node optimization mode, heartbeats to followers are disabled, but ticking/election remain enabled:
- Code path:
backend/crates/kalamdb-raft/src/manager/raft_group.rs enable_heartbeat: falseenable_elect: trueenable_tick: true
This produces a small, steady idle CPU floor.
4. Background scheduler intervals still run
Jobs manager has periodic intervals (leadership checks, polling backoff windows, health monitoring).
- Code path:
backend/crates/kalamdb-core/src/jobs/jobs_manager/runner.rs - Examples:
leadership_intervalevery 1s, adaptive poll interval (500ms to 5000ms), health interval every 30s
5. Docker healthcheck adds minor periodic load
Docker healthchecks run every 30 seconds by default, but this is usually not the dominant idle CPU source.
- Dockerfile:
docker/build/Dockerfile - Compose:
docker/run/single/docker-compose.yml
Why memory is not near 0 MB
Even with an empty database, memory is used by:
- Rust runtime + allocator
- Tokio + Actix thread stacks and schedulers
- RocksDB process state and metadata
- Raft state machines and internal structures
So ~20 MiB idle memory in default container mode is normal for this architecture.
Tuning for lower idle usage
If lower idle footprint is preferred over max local concurrency:
- Set
server.workers = 1inserver.toml. - Reduce
performance.worker_max_blocking_threads(example:64). - Optionally increase healthcheck interval in Docker compose.
Measured impact from tuning
With:
workers = 1worker_max_blocking_threads = 64- healthcheck disabled for measurement isolation
Observed:
- Average idle CPU dropped to about
~0.70% - Idle memory dropped to about
~13.7 MiB - Thread count dropped to about
20
Practical expectation
For a Rust DB server with Actix, Tokio, RocksDB, and single-node Raft initialized:
- Non-zero idle CPU is expected
- Tens of MiB of idle memory is expected
If idle CPU is sustained above a few percent on an empty system, capture profiling data before changing architecture defaults.