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).
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.
The fork and copy-on-write
kernel-tuning.md.txt · Transparent Huge PagesValkey 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.
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.
Memory overcommit, on
kernel-tuning.md.txt · Memory OvercommitThe 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.
On EchoMQ’s valkey.conf
infra/valkey/conf/valkey.conf · the fork budgetThe 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 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:
# 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.
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.
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.
Recap — cheap, allowed, and rare
next → R8.01.2A 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.
References
sources · relatedSources
- Valkey — Diagnosing latency issues — the fork, fsync, and huge-page behaviour the kernel tuning is for.
- Redis — Persistence (RDB and AOF) — why a rewrite forks a child and relies on copy-on-write.
- Redis — Administration — the documented THP and overcommit guidance the source applies, plus the startup warning.
- Redis — Documentation — the persistence and kernel-tuning context. The source is a Shopify RedisDays talk, the Redis docs, and production post-mortems.
Related in this course
- R8.01 · Kernel tuningthe module hub
- R8.01.2 · Latency spikesthe next dive — swappiness, defrag, the command thread
- R8 · Production & Operationsthe chapter
- /bcs/flythe same Valkey machine, set up from inside the BCS stack