Monitoring

Redis mem_fragmentation_ratio Too High? How to Read It and Fix It

Redis says it uses 20 GB, the server says 32 GB, and the alert says fragmentation is 1.6. Sometimes that is real waste, sometimes it is a leftover peak, and sometimes it hides the opposite problem: swapping.

· 13 min read · AG Data Team

A high Redis mem_fragmentation_ratio is one of the most common memory alerts, and one of the most misread. The number compares what the operating system sees with what Redis thinks it has allocated. A value of 1.5 on a 30 GB instance can mean 10 GB of real waste, a harmless leftover from yesterday's peak, or an accounting effect that has nothing to do with your data. A value below 1 is worse: it usually means the kernel has pushed part of Redis to swap. Here is how to read it properly and what to do in each case.

What the ratio actually measures

INFO memory defines mem_fragmentation_ratio as the ratio between used_memory_rss (what the process occupies in RAM, as the OS sees it) and used_memory (what Redis has allocated through its allocator). The documentation is explicit that it does not only include fragmentation, but also other process overheads, code, shared libraries and the stack.

Start by looking at everything together:

redis-cli INFO memory | grep -E '^(used_memory|used_memory_rss|used_memory_peak|mem_fragmentation_ratio|mem_fragmentation_bytes|allocator_frag_ratio|allocator_frag_bytes|allocator_rss_ratio|rss_overhead_ratio|mem_allocator):'

redis-cli MEMORY DOCTOR

Since Redis 4.0, MEMORY DOCTOR also gives a short human-readable report with suggestions. Then read the numbers in this order:

If allocator_frag_ratio is close to 1 while mem_fragmentation_ratio is high, you are not looking at fragmentation in the usual sense.

Cause 1: a past peak, not fragmentation

The most common explanation is described in the Redis memory optimization guide: Redis does not always return memory to the OS when keys are removed. If an instance grew to 5 GB and then 2 GB of keys were deleted, RSS will probably stay around 5 GB while used_memory drops to 3 GB. The freed pages often share space with keys that still exist, so the allocator cannot give them back.

This memory is not lost. When new keys arrive, the allocator reuses the freed space, and RSS stays flat until the data grows past the old size. Compare used_memory_peak with used_memory_rss: if RSS is close to the peak, the ratio reflects history rather than a problem. The guide draws the practical conclusion itself: provision memory for peak usage, and do not trust the fragmentation ratio after a large peak.

Typical triggers are a mass deletion, a batch job that filled the cache for a few hours, or a large eviction wave. We explained how eviction and maxmemory interact in Redis OOM and eviction policies.

Cause 2: real fragmentation

True external fragmentation appears when the workload keeps allocating and freeing values of different sizes: strings that grow and shrink, many keys with short TTLs, hashes and lists that change size constantly. The allocator ends up with many partly used pages. You see it as a high allocator_frag_ratio together with a large allocator_frag_bytes, and it does not go away when the data set grows back.

Note that maxmemory limits what Redis allocates for data; the memory guide says Redis allocates at most that much, apart from small extra allocations. Fragmentation comes on top. A server with maxmemory 24gb and 1.4 real fragmentation needs much more than 24 GB of RAM, and the OOM killer does not care what maxmemory says.

Cause 3: ratio below 1 means swapping

When used_memory is larger than used_memory_rss, the documentation says part of Redis memory has been swapped out by the OS, and you should expect significant latency. This is the dangerous case, and it is easy to miss because alerts are usually set only for high values. The latency guide shows how to confirm it:

redis-cli INFO server | grep process_id
grep Swap: /proc/<pid>/smaps | awk '{s+=$2} END {print s " kB swapped"}'
vmstat 1   # non-zero si/so columns mean swapping is happening now

The fix is less memory pressure, not tuning Redis: more RAM, a lower maxmemory, or moving other memory-hungry processes off the host.

Active defragmentation

Redis 4.0 introduced active defragmentation, which moves values into compact memory regions while the server keeps running. According to redis.conf, it is disabled by default and only works with the jemalloc copy bundled with Redis, which is the default for Linux builds. You can enable it at runtime:

# check that the server uses jemalloc
redis-cli INFO memory | grep mem_allocator

# enable at runtime (defaults shown for the thresholds)
redis-cli CONFIG SET activedefrag yes
redis-cli CONFIG GET active-defrag-*

# watch progress
redis-cli INFO memory | grep -E 'allocator_frag_ratio|active_defrag_running'
redis-cli INFO stats  | grep -E 'active_defrag_(hits|misses|key_hits|key_misses)'

The defaults in Redis 7.4 and 8.0 and in Valkey 8.1 are the same:

Valkey 8.1 adds active-defrag-cycle-us (default 500 microseconds), the length of each defrag cycle, which controls the latency impact on client commands. The config files themselves advise leaving the defaults alone unless you know what you are changing, and enabling the feature only when you actually have fragmentation.

There is also MEMORY PURGE, which asks jemalloc to release dirty pages. It can lower allocator_rss_bytes, but it does not compact anything, so it does not fix real fragmentation.

Large instances: what changes

Our rule of thumb: alert on mem_fragmentation_bytes and on a ratio below 1, not only on a ratio above 1.5. Before enabling defrag, check allocator_frag_ratio. If it is close to 1, the "fragmentation" is a past peak or overhead, and defrag will not help.

Checklist when the alert fires

  1. Check mem_fragmentation_bytes: is the waste large enough to matter?
  2. If the ratio is below 1, check swap in /proc/<pid>/smaps and vmstat first.
  3. Compare used_memory_rss with used_memory_peak to see whether you are looking at a past peak.
  4. Read allocator_frag_ratio and allocator_frag_bytes for true fragmentation.
  5. Confirm mem_allocator is jemalloc, then enable activedefrag in a quiet period and watch latency.
  6. If defrag is not enough or not available, plan a failover to a replica and restart the old primary.
  7. Revisit sizing: peak data plus fragmentation plus fork overhead.

Key takeaways

Redis Valkey Memory Monitoring
Work with us

Redis memory does not add up?

We investigate Redis and Valkey memory problems on production: fragmentation, swapping, fork overhead and sizing, and fix them without losing data or taking the cache down.

Get in touch More from the blog