Optimizing Varnish Cache: Hybrid Memory+Disk Storage Configuration for Resource-Constrained Servers


2 views

When configuring Varnish for production environments, we often face the memory-disk tradeoff. The malloc storage backend offers blazing fast memory access but limited capacity, while file storage provides larger capacity at the cost of slower disk I/O. For sites with relatively static content (like documentation portals or CMS-driven marketing sites), we can implement an elegant hybrid solution.

Varnish supports multiple storage backends simultaneously through its -s parameter. The syntax allows specifying:


# Memory storage (1GB)
-s malloc,1G

# File storage (10GB)
-s file,/var/lib/varnish/storage.bin,10G

Here's a production-tested configuration that prioritizes memory while falling back to disk:


# /etc/default/varnish
DAEMON_OPTS="-a :80 \\
  -T localhost:6082 \\
  -s main=malloc,512m \\
  -s secondary=file,/var/lib/varnish/varnish_storage.bin,5G \\
  -p thread_pool_add_delay=2 \\
  -p thread_pools=4 \\
  -p thread_pool_min=100 \\
  -p thread_pool_max=4000"

The main store will be checked first for objects, followed by secondary. Objects are promoted to faster storage when frequently accessed.

For optimal hybrid performance, add these VCL tweaks:


sub vcl_backend_response {
    # Keep small assets in memory
    if (std.integer(beresp.http.Content-Length, 0) < 1048576) { # 1MB
        set beresp.storage = "main";
    }
    
    # Longer TTL for disk-stored items
    if (beresp.storage == "secondary") {
        set beresp.ttl = 48h;
    }
}

Use these varnishstat commands to validate performance:


varnishstat -1 -f MAIN.n_lru_nuked  # Memory evictions
varnishstat -1 -f SECONDARY.n_lru_nuked # Disk evictions
varnishstat -1 -f MAIN.cache_hit # Memory hit rate
  • Allocate no more than 70% of available RAM to malloc storage
  • Place disk storage on fast SSDs or NVMe devices
  • Monitor disk I/O wait times (vmstat 1)
  • Consider persistent storage for critical assets (Varnish 6+)



Varnish Cache offers multiple storage backends, with malloc (memory) and file (disk) being the most commonly used. While the documentation presents them as distinct options, creative configuration can achieve a hybrid approach.

Here's how to configure Varnish to use both storage types effectively:

# /etc/varnish/default.vcl
vcl 4.1;

backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

sub vcl_init {
    # Primary storage in memory (100MB)
    new mem_cache = storage.malloc(100M);
    
    # Fallback storage on disk (2GB)
    new disk_cache = storage.file("/var/lib/varnish/storage.bin", 2G);
}

To implement a true hybrid approach with fallback behavior, you'll need to customize your VCL:

sub vcl_recv {
    # Try memory cache first
    if (storage.mem_cache.free() > 0) {
        set req.storage_hint = "mem_cache";
    } else {
        set req.storage_hint = "disk_cache";
    }
}

sub vcl_backend_response {
    # Set TTLs differently for each storage
    if (beresp.storage_hint == "mem_cache") {
        set beresp.ttl = 2h;
    } else {
        set beresp.ttl = 24h;
    }
}
  • Memory Allocation: Start with 50-70% of available RAM for malloc
  • Disk Configuration: Use fast storage (SSD preferred) for file backend
  • Monitoring: Track hit/miss ratios for each storage with varnishstat

For more granular control, consider these VCL snippets:

sub vcl_hit {
    # Promote disk cache hits to memory
    if (obj.hits > 3 && obj.storage == "disk_cache") {
        storage.mem_cache.put(obj);
    }
}

sub vcl_backend_fetch {
    # Prefer memory for small objects
    if (std.integer(bereq.http.Content-Length, 0) < 1048576) { # 1MB
        set bereq.storage_hint = "mem_cache";
    }
}

Another configuration option using the newer Varnish syntax:

# Command line parameters
varnishd -s malloc,100M -s file,/var/lib/varnish/storage.bin,2G

Use these commands to verify your configuration:

varnishadm storage.list
varnishstat -1 -f MAIN.*