SMA.<name>.c_fail counts storage allocation failures after LRU eviction. Under normal conditions it stays at zero. When it climbs, memory management is wrong, and the cause is not always “the cache is full.”
The deceptive variant is the malloc stevedore. Over weeks of object churn, the underlying allocator (jemalloc or glibc malloc) fragments the heap. Varnish reports free bytes in SMA.<name>.g_space, but those bytes are scattered across many small free regions that cannot satisfy a contiguous allocation. Varnish evicts objects, retries, and fails. c_fail increments while g_space insists there is room.
What this means
c_fail is a cumulative counter under the SMA (Storage Malloc) or SMF (Storage File) namespace. It increments each time the stevedore cannot satisfy an allocation request after attempting LRU eviction. Every increment is an object Varnish wanted to cache but could not store.
Two conditions produce c_fail:
Real storage exhaustion.
g_spaceis near zero. The cache is genuinely full, and even after evicting, there is not enough contiguous room. Fix: more storage or a smaller working set.Fragmentation-induced failure.
g_spaceshows meaningful free bytes, but the allocator cannot return a contiguous block of the requested size. Varnish evicts, retries, and fails. The cache reports capacity it cannot deliver.
The second condition develops slowly over weeks, is invisible to Varnish’s own accounting, and produces symptoms that look like capacity problems but are allocator pathology.
When an allocation fails, Varnish has a safety valve: the nuke_limit parameter (default 50). If evicting more than nuke_limit objects is required to free enough space for one allocation, Varnish gives up rather than clearing the cache for a single object. MAIN.n_lru_limited counts these events. The object goes uncached and the request is treated as a miss.
flowchart TD
A["c_fail incrementing"] --> B{"g_space near 0?"}
B -- "Yes" --> C["Real storage exhaustion
Cache genuinely full"]
B -- "No, free bytes reported" --> D["Fragmentation suspected"]
C --> E["Increase storage size
or reduce working set"]
D --> F{"Process RSS much larger
than configured storage?"}
F -- "Yes" --> G["Check transient storage
and allocator overhead"]
F -- "No" --> H["Heap fragmentation
Consider restart or
alternative stevedore"]Common causes
| Cause | What it looks like | First thing to check |
|---|---|---|
| Cache too small for working set | g_space near 0, n_lru_nuked high, hit rate declining | g_bytes / (g_bytes + g_space) ratio |
| Malloc fragmentation | c_fail climbing but g_space shows free bytes, RSS growing over weeks | Process RSS vs configured -s size |
| Transient storage growth | RSS growing, SMA.Transient.g_bytes climbing, hitpass/hitmiss elevated | varnishstat -1 -f SMA.Transient.* |
| Large objects exhausting storage | Few allocations consuming disproportionate space, hit rate variable | Average object size: g_bytes / g_alloc |
| Allocator bug (jemalloc 5.2.1) | RSS grows monotonically regardless of object churn | ldd $(which varnishd) | grep jemalloc |
| Oversized storage allocation | -s malloc,SIZE set to most or all of system RAM, OOM killer fires | System dmesg for OOM events |
Quick checks
These commands are read-only and safe for production.
# Current allocation failure count and storage state
varnishstat -1 -f 'SMA.s0.c_fail' -f 'SMA.s0.g_bytes' -f 'SMA.s0.g_space' -f 'SMA.s0.g_alloc'
# LRU nuking rate and expiry
varnishstat -1 -f MAIN.n_lru_nuked -f MAIN.n_expired
# Transient storage (unbounded by default)
varnishstat -1 -f 'SMA.Transient.*'
# Process RSS in KB (compare against configured -s size)
ps -p $(pgrep -n varnishd) -o rss=
# Allocator Varnish is linked against
ldd $(which varnishd) | grep -i 'jemalloc\|malloc'
# Transparent Huge Pages state (relevant for jemalloc)
cat /sys/kernel/mm/transparent_hugepage/enabled
How to diagnose it
Confirm c_fail is climbing. Take two readings 60 seconds apart and compute the delta. A one-time bump from process start is noise. A sustained rate is the problem.
Check g_space. If near zero, you have real storage exhaustion, not fragmentation. Skip to the cache-sizing fix below.
Check average object size. If
g_spaceshows free bytes butc_failis climbing, computeg_bytes / g_alloc. If this is reasonable (10-100 KB) but allocations still fail, the free space is fragmented.Compare RSS to configured storage. RSS significantly larger than your
-s malloc,SIZEmeans either transient storage is growing or the allocator is retaining freed memory. jemalloc in particular holds virtual memory and may not return it to the OS afterfree().Check transient storage.
SMA.Transient.g_bytestracks memory for uncacheable responses (pass, hit-for-miss, pipe). Transient storage is unbounded by default and is a common OOM path. If it is growing, the problem may not be in your primary storage at all.Check the allocator version. libjemalloc 5.2.1 has a known memory allocation issue on Linux. libjemalloc 5.3.0 fixes it. Upgrading the library may resolve monotonic RSS growth without any Varnish configuration change.
Check THP state. Transparent Huge Pages interact poorly with jemalloc, causing memory over-consumption. If THP is
alwaysormadvise, setMALLOC_CONF=thp:neverin the Varnish process environment.Correlate with hit rate and backend load. If
c_failis climbing, hit rate is declining, andbackend_reqincreases, the allocation failures are causing real user impact: objects that should be cached are not being stored.
Metrics and signals to monitor
| Signal | Why it matters | Warning sign |
|---|---|---|
SMA.<name>.c_fail | Allocation failures after eviction | Any sustained nonzero rate |
SMA.<name>.g_space | Bytes Varnish believes are available | Near zero with exhaustion; nonzero with fragmentation |
SMA.<name>.g_bytes | Bytes currently in use | Trending toward configured max |
SMA.<name>.g_alloc | Current allocation count | Combined with g_bytes, reveals average object size |
MAIN.n_lru_nuked | Objects evicted to make room | Rate exceeding n_expired rate means storage-bound, not TTL-bound |
SMA.Transient.g_bytes | Uncacheable response memory | Growing monotonically means pass or hitmiss pressure |
| Process RSS | Actual footprint vs configured storage | RSS exceeding 130% of -s size signals fragmentation or transient growth |
MAIN.cache_hit ratio | User-facing consequence of storage failures | Declining while c_fail climbs confirms user impact |
Fixes
Cache too small for the working set
If g_space is genuinely near zero, the cache cannot hold your active working set. Options:
- Increase
-s malloc,SIZE. Reserve 20-30% of system RAM for the OS, Varnish process overhead, thread stacks, workspace, and transient storage. Allocating all system RAM to storage is the most common path to OOM. - Reduce the working set. Exclude large or uncacheable objects. Identify them with
varnishtop -I ObjHeader:Content-Length. - Shorten TTLs for low-value content so objects expire naturally instead of occupying storage.
Malloc fragmentation confirmed
If g_space shows free bytes but allocations fail, the heap is fragmented. This is a property of the allocator, not Varnish’s accounting. Varnish tracks bytes in and out of malloc() and free(); it has no visibility into allocator-internal fragmentation.
Immediate fix: restart the child process to clear the heap and reset fragmentation state. Schedule during a low-traffic window. The cache will be cold afterward.
Medium-term mitigations:
- Switch to the file stevedore (
-s file). File-backed storage uses memory-mapped pages and is not subject to the same fragmentation pattern. Performance is comparable until memory pressure forces paging. - Tune jemalloc. For jemalloc-based builds,
MALLOC_CONFparameters such asdirty_decay_ms(jemalloc 5.x) orlg_dirty_mult(older versions) can reduce fragmentation waste at a modest performance cost. - Consider MSE (Massive Storage Engine). Varnish Software’s proprietary MSE stevedore is designed to be fragmentation-proof by breaking objects into fixed-size fragments managed in LRU zones.
Transient storage growth
If SMA.Transient.g_bytes is growing without bound, uncacheable traffic is consuming memory.
- Identify what is being passed:
varnishlog -q 'VCL_call eq "PASS"'to see URL and header patterns. - Fix the VCL or application to cache content that should be cacheable.
- Cap transient storage with
-s Transient=malloc,1G. This prevents unbounded growth at the cost of hard-limiting transient capacity.
Oversized storage allocation
If Varnish is being OOM-killed, -s malloc,SIZE is likely too aggressive. The OS needs memory for page tables, kernel structures, other processes, and the Varnish management process. Reduce the storage size by 20-30% or add system RAM.
Prevention
- Size storage conservatively. Allocate at most 70-80% of available RAM to malloc storage. The remainder covers allocator overhead, process overhead, thread stacks, workspace, and transient storage.
- Monitor RSS against configured storage. RSS beyond the configured storage size is the leading indicator of fragmentation or transient growth. Alert on RSS exceeding 130% of the configured
-ssize as a sustained condition. - Schedule periodic restarts for long-running malloc instances. If fragmentation accumulates over weeks, a planned restart during a maintenance window is less disruptive than an unplanned OOM. Monitor the fragmentation trend to determine cadence.
- Disable THP for the Varnish process. Set
MALLOC_CONF=thp:neverin the process environment. - Upgrade jemalloc if on 5.2.1. Version 5.3.0 resolves the known allocation problem causing monotonic RSS growth.
- Cap transient storage. Use
-s Transient=malloc,SIZEto prevent unbounded transient growth from consuming memory the primary cache needs. - Track average object size. Monitor
g_bytes / g_allocover time. A sudden shift may indicate a change in what your application is caching, affecting storage sizing assumptions.
How Netdata helps
Netdata collects Varnish SMA counters at per-second resolution, making the correlation between c_fail, g_space, and process RSS visible without manual polling.
- Per-second c_fail rate. Netdata computes the rate from the cumulative counter automatically, showing allocation failures per second.
- g_space vs c_fail correlation. Displayed on the same timeline, the fragmentation signature is immediately visible:
c_failclimbing whileg_spaceremains nonzero. - Process RSS alongside storage counters. RSS from
/procis visible next to Varnish’s own storage accounting, so growth beyond the configured-ssize stands out. - Eviction pressure and hit rate together.
n_lru_nukedalongsidecache_hitratio on one timeline shows whether storage problems are affecting cache effectiveness. - Transient storage tracking. Continuous collection of
SMA.Transient.g_bytescatches slow growth before the OOM killer does. - ML anomaly detection on RSS. Slow RSS growth over weeks is exactly the pattern that threshold-based alerts miss but anomaly detection catches.
Related guides
- Varnish Error 503 Backend fetch failed: what the error page actually means
- Varnish backend_fail, backend_unhealthy, and backend_busy: three different backend problems
- Varnish backend connection reuse low: keepalive not working and slow TTFB
- Varnish backend probe configuration: threshold, window, interval, and initial
- Varnish backend is sick: health probes, all-backends-sick, and grace
- Varnish cache hit ratio dropped: hit rate collapse and backend overload
- Varnish cache stampede: a popular object expires and the herd hits the backend
- Varnish ESI errors: broken pages and workspace pressure from Edge Side Includes
- Varnish fetch_failed: backend connected but the fetch broke
- Varnish grace masking a backend outage: the ticking-clock incident
- Varnish Guru Meditation: reading the XID and tracing the failing request
- Varnish cache_hitpass / cache_hitmiss climbing: uncacheable content bleeding to the backend






