Memory limits and host sizing

DataMind OS gives every service a memory limit and a memory reservation, sized from the host's own RAM. The DataMind Installer calculates them, writes them into deployment/.env, and checks that the host can enforce them. The calculation is made when it is asked for; it is never stored.

Change the values in Configuration. This page explains what the numbers mean, how they move, and what the host must provide.

Where the limits live

The limits sit in deployment/.env, in a generated block between two marker comment lines: one starts with # >>>, the other with # <<<. The Installer rewrites the block every time it generates the file, so on every save, install and update.

Important

A hand edit inside the generated block is lost at the next save, install or update. Edit the rows in Configuration instead; there your values are kept.

Service rows come first, the host's rows last:

RowWhat it carries
<SERVICE>_MEM_LIMITThe ceiling for a service's container; a container that goes over it is killed
<SERVICE>_MEM_RESERVATIONThe memory the service is guaranteed
<SERVICE>_OOM_SCORE_ADJThe service's place in the kill order; see The kill order
<SERVICE>_SLICEPresent for protected services, which run in a memory slice of their own
<SERVICE>_ENABLEDtrue or false, for services that can be switched off
MEMORY_POOL_MBThe pool the calculation worked from

Above the rows, comment lines record how the block was made: when it was generated, the host, its class, the pool and the host reserve, the reservation budget, and whether anything was scaled. When your edits are in play, one line lists them: # hand-edited, dependent rows recalculated from them: <codes>.

The host classes

Available memory does not run out silently. earlyoom, the host's memory killer, watches it: below EARLYOOM_SIGTERM_BELOW it asks processes to stop, and below EARLYOOM_SIGKILL_BELOW it kills them. Both thresholds follow the host's class, and the class follows the host's RAM:

ClassCovers hosts withEARLYOOM_SIGTERM_BELOWEARLYOOM_SIGKILL_BELOW
smallunder 32 GiB3072m1536m
medium32 GiB or more, under 64 GiB4096m2048m
large64 GiB or more, under 128 GiB6144m3072m
xlarge128 GiB or more, under 256 GiB10240m5120m
xxlarge256 GiB or more (the catch-all class)16384m8192m

The boundaries exclude the upper value: a host with exactly 32 GiB is medium, and a host one MiB smaller is small. Hosts of 256 GiB or more all land in xxlarge. Sizes on this page are binary, as the Installer writes them: 1 GiB is 1024 MiB.

For choosing a host's size in the first place, see System requirements.

The pool and the reservation budget

Two numbers bound the plan:

NumberWhat it is
The poolThe host's RAM minus a 10% reserve for the host itself. Every limit and reservation is sized from it, and it is written as MEMORY_POOL_MB
The reservation budget75% of the pool

When the calculated reservations do not fit the budget, the Installer scales them down rather than drop them (never below 16m each), keeps your hand-edited values as they are, and records it in the comment lines.

The calculation reports a few flags with the plan:

FlagWhat it means
scaledThe machine could not fit the configured reservations, so they were shrunk. Treat it as a sizing signal: the host is smaller than the plan wants
conflictsCodes the Installer wanted to write but could not, because the template already owns the code or two services claim the same one. Nothing is written for them
problemsHand edits the slice script would refuse, or values that cannot be read. Deploys are refused while this is not empty; see When the settings block a deploy
blockingThe calculation cannot produce a usable plan at all. Deploys are refused while it is in this state

The kill order

When memory runs short, the host kills the process with the highest OOM score first. A service's score starts from its tier bias and drops with its reservation:

The result is rounded and kept within -999 and 1000. A batch service that reserves about a tenth of RAM scores around 500; a critical service that reserves about a third scores around -333. The higher a score sits, the sooner that service gives way, so batch work yields before core services.

Edit a memory value

A memory row in Configuration shows the calculated value until you replace it. Type a new value and save; the calculation keeps yours and recalculates the rows that depend on it.

The rowIt accepts
A per-service memory valueA whole number with an optional unit: m, mb, mib, g, gb or gib, any case. 8g is saved as 8192m, and a bare number means MiB
A row the memory-slice script reads on the hostOnly a whole number of MiB with a lowercase m, such as 1024m. An uppercase unit is refused here
An OOM score rowA whole number, such as -500
An _ENABLED rowtrue or false

A value that does not fit its row is refused as <CODE> is '<value>', expected <what the row accepts>. The expectation text names the rule, for example a whole number of MiB with a lowercase m for a row the host script reads. A value containing a line break is refused as <CODE> contains a line break.

When the settings block a deploy

The Installer refuses to deploy or apply configuration while the plan has problems or is blocking, and says which:

Each problem names its rows. The ones you can hit:

The problemWhat it means
Protected memory <n> MiB exceeds 75% of the <pool> MiB pool (<budget> MiB)The protected services' reservations together exceed the budget. Example: Protected memory 30000 MiB exceeds 75% of the 28882 MiB pool (21661 MiB). Lower a protected reservation, or give the host more RAM
<RESERVATION> is <n> MiB, above <LIMIT> <m> MiBA reservation sits above its own limit. Example: CLICKHOUSE_MEM_RESERVATION is 5000 MiB, above CLICKHOUSE_MEM_LIMIT 4000 MiB. Raise the limit, or lower the reservation
Edited reservations sum to <n> MiB, above the <m> MiB reservation budgetYour edits alone exceed the budget. Lower or reset some
EARLYOOM_SIGKILL_BELOW is <n> MiB, above EARLYOOM_SIGTERM_BELOW <m> MiBThe kill threshold sits above the ask threshold. The kill value must be the lower of the two
The slices claim more MiB than the slice minimum row allowsThe slice rows disagree about the same memory. Reset the hand edits, or align the rows

Conflicts do not block anything: a conflicting code is simply left unwritten. Fix the rows a problem names, save, and run the action again. Deploys run from Service status.

Host prerequisites for memory slices

The limits are applied to the host by deployment/apply-memory-slices.sh, a script the Installer downloads with each deploy (see What lives on the host). Before it applies them, it checks seven things, and all seven must pass:

CheckPasses whenThe detail reports
cgroup v2cgroup v2 is mountedcgroup v2 is mounted, or /sys/fs/cgroup/cgroup.controllers not found
Kernel 5.9 or newerThe kernel is 5.9 or newerKernel <version>
memory_recursiveprotcgroup v2 is mounted with memory_recursiveprotcgroup2 is mounted with memory_recursiveprot, or cgroup2 is mounted without memory_recursiveprot
Swap offThe host has no swapSwap <n> MiB
RAM 15 GiB or moreTotal RAM is at least 15 GiB<total> MiB, at least <needed> MiB needed
Docker cgroup driver systemdDocker uses the systemd cgroup driverCgroup driver <driver>
Rootful DockerDocker runs as rootDocker runs as root, or Docker runs rootless

When a check cannot run at all, its detail says why: Host could not be inspected: ... or Docker could not be inspected: ....

The slice script can refuse too:

Reset a hand edit

Behind every hand value the calculation still keeps the value it would have chosen. A reset brings it back:

Each reset runs behind a preview first, and a preview writes nothing. The outcomes are Value reset to the calculated one and Memory values reset to the calculated ones. A reset is refused when it would make the memory problems worse; the preview says why.

Rows the calculation does not own cannot be reset: Configuration "<code>" is not a calculated memory row and cannot be reset. The host's fixed slice rows cannot be changed or reset: Configuration "<code>" is a fixed systemd slice name and cannot be changed.

The Reset controls are on Configuration.

Questions, answered

Why did the size I typed become a different number?

Sizes are saved in MiB. 8g becomes 8192m, and a bare number means MiB. The form accepts m, mb, mib, g, gb and gib in any case; a few rows that the host script reads accept only a lowercase m.

Can I edit the memory limits in deployment/.env directly?

No. The block is rewritten on every save, install and update, so edits made in the file are lost. Edit the rows in Configuration: your value is kept, and the rows that depend on it are recalculated.

The calculation says my values were scaled. Is something wrong?

No. The configured reservations did not fit the reservation budget, so the Installer shrank them, and the plan fits the host again. Treat it as a sizing signal, and review the edited reservations or the host's RAM.

Why does the Installer refuse a deploy because of memory settings?

The plan has problems or is blocking. The refusal names what to fix: Memory settings are invalid: <problems separated by "; ">. Fix the rows each problem names, then run the action again; the details are in When the settings block a deploy.

What does "Protected memory exceeds 75% of the pool" mean?

The protected services reserve more together than the reservation budget allows, which is 75% of the pool. The message shows the exact numbers; lower a protected reservation, or give the host more RAM.

A reservation is above its limit. How do I fix it?

Raise the limit above the reservation, or lower the reservation. A reservation must fit inside its own limit, and the Installer refuses the plan while one does not. The message reads CLICKHOUSE_MEM_RESERVATION is 5000 MiB, above CLICKHOUSE_MEM_LIMIT 4000 MiB, using your own rows.

Why do two hosts with almost the same RAM get different limits?

They fall into different host classes: a host with exactly 32 GiB is medium, and one MiB smaller is small. Inside a class, the rows are sized from each host's own pool, so they differ with RAM.

What happens when the host runs short on memory?

earlyoom steps in: below the class's EARLYOOM_SIGTERM_BELOW it asks processes to stop, and below EARLYOOM_SIGKILL_BELOW it kills them, highest OOM score first. Batch services give way before critical ones.

Why does an OOM score show a negative number?

The score starts as the tier bias (600 for batch, 0 for critical) and drops by 1000 times the service's reservation share of RAM, so most scores are negative. Scores are kept within -999 and 1000, and a higher score is killed first.

How do I undo my memory edits?

Reset them: Reset on a row, or Reset all hand-edited memory limits. Each reset is previewed first, showing the calculated value that returns and any other row that moves with it. The outcomes are Value reset to the calculated one and Memory values reset to the calculated ones; the controls are on Configuration.

Which checks must a host pass before memory slices are applied?

Seven: cgroup v2, Kernel 5.9 or newer, memory_recursiveprot, Swap off, RAM 15 GiB or more, Docker cgroup driver systemd and Rootful Docker. Each check reports what it found; fix the host and check again. See Host prerequisites for memory slices.