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-cliavailable 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.
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,setWhat 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,maxmemoryis 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.
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 yesThen make it permanent in /etc/redis/redis.conf:
maxmemory 3gb
maxmemory-policy allkeys-lru
maxmemory-samples 5
lazyfree-lazy-eviction yesChoosing 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:
save ""
appendonly noWarning: 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:
save 900 1
appendonly yes
appendfsync everysec
no-appendfsync-on-rewrite yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 256mbappendfsync 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:
sudo systemctl restart redis-serverOn 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.
sudo sysctl -w vm.overcommit_memory=1
sudo sysctl -w net.core.somaxconn=65535
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabledMake the sysctls survive a reboot in /etc/sysctl.d/99-redis.conf:
vm.overcommit_memory = 1
net.core.somaxconn = 65535vm.overcommit_memory=1lets Redis fork for a background save even when memory looks tight. Without it, the fork fails and you getMISCONFerrors.net.core.somaxconnmust matchtcp-backloginredis.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
echoabove only lasts until reboot.
In /etc/redis/redis.conf, align the networking values:
tcp-backlog 65535
tcp-keepalive 300
timeout 0If the instance is CPU-bound on reads and the VPS has several cores, Redis 6 and later can use background I/O threads:
io-threads 2
io-threads-do-reads yesKeep 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:
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 getYou 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 ofsavepoints, or move persistence to a replica. evicted_keysclimbing and hit ratio falling. Cause:maxmemorytoo small or the wrong policy. Fix: raisemaxmemory, switch toallkeys-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: checkdf -handdf -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=0plus a fork, ormaxmemoryset above real RAM. Fix: setvm.overcommit_memory=1and lowermaxmemory. - Clients time out under load while CPU is idle. Cause: the accept backlog is full. Fix: raise
net.core.somaxconnandtcp-backlogtogether, then restart Redis.
Next steps
- Revisit your install and access rules with install and secure Redis on a Linux VPS.
- If the VPS is short on RAM, add a swap file as a safety net — but keep
maxmemorylow enough that Redis never touches it. - Running a database alongside Redis? Tune MySQL and MariaDB memory settings for a small VPS so the two do not fight for the same pages.
