Control panels

Optimizing Redis for high-read, low-latency applications

Tune maxmemory, eviction and persistence so Redis answers read-heavy traffic in under a millisecond, and learn which kernel settings stop latency spikes.

AdvancedLinux server7 min read

To optimize Redis for a high-read, low-latency application you keep the working set in RAM, stop the server from forking at the wrong moment, and remove the kernel settings that cause multi-millisecond stalls. This guide walks through measuring your current instance, setting maxmemory and an eviction policy, choosing persistence that matches your data, and applying the sysctl and redis.conf changes that matter most. It assumes a read-heavy workload such as a cache, session store or feed, on Ubuntu 22.04/24.04, Debian 12, AlmaLinux or Rocky 8–9.

Before you start

  • A Linux VPS with Redis already installed and secured. If you have not done that yet, follow install and secure Redis on a Linux VPS first.
  • SSH access as a sudo user. See create a sudo user if you only have root.
  • redis-cli available on the server.
  • A clear answer to one question: is this data disposable? A cache can lose everything on restart. A session store or queue usually cannot.
  • Know how much RAM the VPS has (free -h) and roughly how large your dataset is.

Warning: Some steps restart Redis, and one option disables persistence entirely. If this instance holds the only copy of your data, take a backup of /var/lib/redis/dump.rdb before you change anything.

Measure the baseline

Tuning without numbers is guesswork. Collect four things first.

Bash
redis-cli INFO memory | grep -E 'used_memory_human|maxmemory_human|mem_fragmentation_ratio'
redis-cli INFO stats | grep -E 'keyspace_hits|keyspace_misses|evicted_keys|expired_keys'
redis-cli --latency -h 127.0.0.1 -p 6379
redis-benchmark -q -n 100000 -c 50 -t get,set

What to look for:

  • Hit ratio. keyspace_hits / (keyspace_hits + keyspace_misses) should be well above 0.9 for a cache. A low ratio means keys are expiring or being evicted too early.
  • evicted_keys. If this climbs during normal traffic, maxmemory is too small or the policy is wrong.
  • mem_fragmentation_ratio. Between 1.0 and 1.5 is normal. Above 1.5 you are wasting RAM; below 1.0 means Redis is swapping, which is the worst case.
  • redis-cli --latency. Prints a running average until you press Ctrl+C. On a healthy instance on the same host you should see sub-millisecond numbers.

Keep the redis-benchmark output so you can compare after tuning.

Set maxmemory and an eviction policy

Without maxmemory, Redis grows until the kernel OOM killer ends the process. Set a ceiling below total RAM — leave room for the OS, for copy-on-write during a fork, and for other services. On a 4 GB VPS, 2.5–3 GB is a reasonable starting point.

Bash
redis-cli CONFIG SET maxmemory 3gb
redis-cli CONFIG SET maxmemory-policy allkeys-lru
redis-cli CONFIG SET maxmemory-samples 5
redis-cli CONFIG SET lazyfree-lazy-eviction yes

Then make it permanent in /etc/redis/redis.conf:

INI
maxmemory 3gb
maxmemory-policy allkeys-lru
maxmemory-samples 5
lazyfree-lazy-eviction yes

Choosing the policy:

  • allkeys-lru — pure cache. Any key can be dropped. This is the usual choice for read-heavy workloads.
  • allkeys-lfu — better when a small set of keys gets most of the reads (Redis 4 and later). It keeps the hot set and drops the long tail.
  • volatile-lru / volatile-lfu — only keys with a TTL can be evicted. Use this when some keys must never disappear, and make sure everything else has an expiry set.

lazyfree-lazy-eviction yes frees evicted values in a background thread, which keeps the main thread responsive when eviction is heavy.

Tip: If you use volatile-* policies, run redis-cli INFO keyspace and check that your cache keys actually have TTLs. Keys without a TTL become unevictable and Redis will return out-of-memory errors once maxmemory is reached.

Choose persistence settings for speed

Persistence is the biggest source of latency spikes in a read-heavy instance. RDB snapshots fork the process, and AOF fsync calls block writes.

For a pure cache, turn both off:

INI
save ""
appendonly no

Warning: With save "" and appendonly no, everything in Redis is lost on restart or crash. Only do this if the data can be rebuilt from your database.

If the data must survive a restart, keep persistence but make it cheaper:

INI
save 900 1
appendonly yes
appendfsync everysec
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 256mb

appendfsync everysec gives you at most one second of loss and keeps fsync off the critical path most of the time. Avoid appendfsync always on a read-heavy instance unless you genuinely need per-write durability — it costs far more than it returns here.

Apply the file changes with a restart:

Bash
sudo systemctl restart redis-server

On AlmaLinux and Rocky the unit is usually redis instead of redis-server. Check with systemctl status redis if the first command fails.

Tune the kernel and networking

Three kernel settings cause most of the "Redis is fast but sometimes slow" complaints.

Bash
sudo sysctl -w vm.overcommit_memory=1
sudo sysctl -w net.core.somaxconn=65535
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled

Make the sysctls survive a reboot in /etc/sysctl.d/99-redis.conf:

INI
vm.overcommit_memory = 1
net.core.somaxconn = 65535
  • vm.overcommit_memory=1 lets Redis fork for a background save even when memory looks tight. Without it, the fork fails and you get MISCONF errors.
  • net.core.somaxconn must match tcp-backlog in redis.conf, otherwise connections queue up and clients time out under load.
  • Transparent Huge Pages cause latency spikes of tens of milliseconds during fork. Disable them permanently with a systemd unit or your distribution's documented method — the echo above only lasts until reboot.

In /etc/redis/redis.conf, align the networking values:

INI
tcp-backlog 65535
tcp-keepalive 300
timeout 0

If the instance is CPU-bound on reads and the VPS has several cores, Redis 6 and later can use background I/O threads:

INI
io-threads 2
io-threads-do-reads yes

Keep io-threads at or below the number of available cores. On a 1–2 vCPU VPS, leave it commented out — it will not help.

Check it works

Re-run the same measurements and compare:

Bash
redis-cli INFO memory | grep -E 'used_memory_human|maxmemory_human|mem_fragmentation_ratio'
redis-cli INFO stats | grep -E 'evicted_keys|rejected_connections|keyspace_hits|keyspace_misses'
redis-cli --latency-history -h 127.0.0.1 -p 6379
redis-benchmark -q -n 100000 -c 50 -t get

You want evicted_keys to stay flat or grow slowly, rejected_connections at zero, and latency that stays under a millisecond with no periodic spikes. Run redis-cli --latency-history for a few minutes so a background save has a chance to happen while you watch.

Troubleshooting

  • Latency spikes every few minutes, then back to normal. Cause: RDB fork or Transparent Huge Pages. Fix: confirm THP is off (cat /sys/kernel/mm/transparent_hugepage/enabled), reduce the number of save points, or move persistence to a replica.
  • evicted_keys climbing and hit ratio falling. Cause: maxmemory too small or the wrong policy. Fix: raise maxmemory, switch to allkeys-lfu, or add TTLs so cold keys expire on their own.
  • MISCONF Redis is configured to save RDB snapshots but is currently not able to persist to disk. Cause: the disk is full, inodes are exhausted, or the Redis user cannot write to the data directory. Fix: check df -h and df -i, and see fix "No space left on device" when the disk isn't full.
  • Redis killed by the kernel (OOM). Cause: vm.overcommit_memory=0 plus a fork, or maxmemory set above real RAM. Fix: set vm.overcommit_memory=1 and lower maxmemory.
  • Clients time out under load while CPU is idle. Cause: the accept backlog is full. Fix: raise net.core.somaxconn and tcp-backlog together, then restart Redis.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.