jonnify·redis /redis-patterns/production-operations/kernel-tuning/huge-pages-overcommit

R8.01.1 · Kernel tuning — dive 1

The fork’s two settings: huge pages & overcommit.

Valkey forks a child for an AOF rewrite and relies on copy-on-write. Two kernel settings determine whether that fork stays cheap and whether the kernel allows it at all.

Grounding: production case study (kernel-tuning.md.txt, the 500× THP amplification) · infra/valkey/conf/valkey.conf (the fork budget, verbatim) · BCS B8.2 (the two settings, from the inside).

Trace a fork — THP on vs off. The child shares the parent’s pages until a write touches one; select a setting to see the size of the page that copy duplicates.
parentserving commands child (fork)AOF rewrite shared physical pages (copy-on-write) copy 2 MB copy 4 KB
readout · Select a setting. The child shares the parent’s pages read-only until a live write forces a copy; THP sets how big that copy is.

Static verdicts (from the source) — THP on → a single-byte write copies a 2 MB page, a 500× amplification, with latency spikes of 10–100× during a rewrite · THP off → the same write copies a 4 KB page, the spike avoided.

§1

The fork and copy-on-write

kernel-tuning.md.txt · Transparent Huge Pages

Valkey runs command execution on a single thread, so it cannot pause the world to write a snapshot. Instead it forks a child process and lets the child do the slow work. For an append-only-file rewrite, the child reads a consistent point-in-time view of the keyspace and writes the compacted log while the parent keeps serving commands.

The fork would be ruinous if it copied the whole heap. It does not. Linux gives parent and child the same physical pages and marks them read-only; the pages stay shared until one side writes. That is copy-on-write (COW): a page is duplicated only at the moment a write touches it, and only that one page. A child that reads without writing — the rewrite child — copies almost nothing. The parent copies a page only when a live command modifies it during the rewrite window.

So the cost of a fork is not the size of the dataset. It is the rate of writes during the rewrite times the size of the unit the kernel copies per write. That unit is what the first setting controls; whether the fork is allowed to start at all is the second.

fork()
Spawns the child that writes the rewrite. The parent keeps answering commands.
copy-on-write
Parent and child share pages read-only; a page is copied only when one side writes it.
the copied unit
A page. THP sets it to 2 MB; with THP off it is 4 KB.
the rewrite window
While the child writes the AOF, every parent write may trigger one page copy.

A fork is cheap because of copy-on-write. This dive is the two settings that keep it that way: how small the copied page is, and whether the kernel lets the fork start.

§2

Transparent huge pages, off

kernel-tuning.md.txt · THP — Fix (required)

A normal memory page is 4 KB. Transparent huge pages (THP) is a kernel feature that hands out 2 MB pages instead, to cut page-table pressure on large-heap workloads. For an in-memory store under copy-on-write it is the wrong trade.

The source states the mechanism plainly: with THP enabled the kernel uses 2 MB pages instead of 4 KB, so when the parent modifies a single byte during a rewrite the kernel must copy the entire 2 MB page — a 500× amplification of the work a 4 KB copy would have done. The visible symptoms in the source are latency spikes of 10–100× during BGSAVE or BGREWRITEAOF, memory usage doubling temporarily during persistence, and client timeouts during background saves.

The fix is to disable it. Write never to the kernel’s THP knob:

# the source's required form — disable transparent huge pages
echo never > /sys/kernel/mm/transparent_hugepage/enabled

Make it permanent under systemd so it survives a reboot, as a pre-start step on the service:

# run it before the server starts
[Service]
ExecStartPre=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/enabled'

Valkey logs a warning at startup if THP is still enabled. That warning is not noise — it is the engine reporting that a single-byte write during a fork will cost a 2 MB page copy. Address it, never ignore it.

THP is a kernel setting, written under /sys. It is not a valkey.conf directive: the config file tunes the server, the kernel knob tunes the host the server forks on.

THP off keeps the copied unit at 4 KB. A single-byte write during a rewrite then copies one small page, not a 2 MB one — the 500× amplification removed at its root.

§3

Memory overcommit, on

kernel-tuning.md.txt · Memory Overcommit

The second setting is about whether the fork is allowed, not how cheap it is. The fork() call can fail when the kernel sizes the child as if it needs as much memory as the parent.

The source describes the trap: when Valkey forks, the kernel pessimistically reserves enough memory for the child to hold a full copy of the parent. On a box with most of its RAM already used, the fork can fail even though copy-on-write means almost no real memory is needed — the child shares the parent’s pages, it does not duplicate them. A pessimistic reservation refuses a fork that would have been free.

The fix tells the kernel to trust copy-on-write:

# let the kernel grant the allocation; COW means the claim is never realized
sysctl vm.overcommit_memory=1

Persist it in /etc/sysctl.conf:

vm.overcommit_memory=1

Setting vm.overcommit_memory=1 makes the kernel always grant the allocation, trusting that copy-on-write means the child’s nominal claim is never realized. Like THP, this is a kernel setting applied with sysctl, not a line in valkey.conf.

Overcommit on makes the fork legal. THP off made the copy small; this keeps the kernel from refusing a fork that copy-on-write would have made nearly free.

§4

On EchoMQ’s valkey.conf

infra/valkey/conf/valkey.conf · the fork budget

The course’s worked engine is the Valkey that backs EchoMQ — the owned bus over the braced emq:{q}: keyspace, the store the codemojex game’s queue runs on. Its real config sits at infra/valkey/conf/valkey.conf, and two of its lines exist to keep the fork cheap and rare.

maxmemory 512mb is a loud guardrail, not a working ceiling: the live dataset is single-digit megabytes (round leaderboards, presence, in-flight stream entries), so 512 MB sits far above it, leaving — in the file’s own words — ~half the box for fork copy-on-write during an AOF rewrite. The headroom THP and overcommit make usable is the headroom this line budgets.

save "" disables RDB snapshotting, which leaves the AOF rewrite as the one fork source. The file’s comment is explicit — one fork source — so RDB does not compete for a second fork. With appendonly yes and a single fork source, the copy-on-write spike is paid once per rewrite, not split across two competing children.

The valkey.conf file carries no THP or overcommit line, and it must not. THP and overcommit are host kernel settings (/sys and sysctl); the config file tunes the server process. The two layers cooperate: the kernel makes the fork cheap and allowed; the config budgets the headroom and keeps a single fork source.

the application · the fork budget the config leaves

The lines that reserve the room

The kernel settings make a fork cheap and legal; these committed lines set how much room it has and how often it happens — verbatim from the real config:

infra/valkey/conf/valkey.conf · the fork budgetfrozen
# Memory: ~half the box left for fork copy-on-write during an AOF rewrite
maxmemory 512mb
maxmemory-policy noeviction

# Persistence: AOF is the single source of durability. One fork source.
appendonly yes
save ""                       ← RDB off — no second fork to compete

Notes on ValkeyA fork for an AOF rewrite, the fsync, and huge-page behaviour are the documented causes of latency between commands — the engine’s own guide to diagnosing them is valkey.io/topics/latency.

the pattern

A forking in-memory store needs THP off so a single-byte write copies a 4 KB page not a 2 MB one, and overcommit on so copy-on-write may forgo memory it never uses. The kernel makes the fork cheap and allowed.

its EchoMQ application

valkey.conf budgets the headroom: maxmemory 512mb leaves ~half the box for COW during an AOF rewrite, and save "" keeps one fork source so the spike is paid once.

Two kernel settings, one config posture. THP off makes a copy-on-write page small; overcommit on makes the fork legal; and EchoMQ’s valkey.conf leaves the room for it and limits it to a single AOF rewrite.

§5

Recap — cheap, allowed, and rare

next → R8.01.2

A fork is cheap because of copy-on-write, and copy-on-write is cheap because the copied unit is small and the fork is allowed. THP off keeps the unit at 4 KB; vm.overcommit_memory=1 keeps the fork from being refused; EchoMQ’s maxmemory 512mb and save "" reserve the headroom and hold to one fork source. The next dive keeps the other thread fast — the single command thread the fork must never stall: swappiness, defragmentation, and the I/O-thread budget that protect tail latency between rewrites.

§6

References

sources · related

Sources

Related in this course