This might be easy question but I am having a hard time finding the answer. How does Redis 2.0 handle running out of maximum allocated memory? How does it decide which data to remove or which data to keep in memory?

5 Answers
5

If you have virtual memory functionality turned on (new in version 2.0 or 2.2, I think), then Redis starts to store the "not-so-frequently-used" data to disk when memory runs out.

If virtual memory in Redis is disabled, it appears as if the operating system's virtual memory starts to get used up (i.e. swap), and performance drops tremendously.

Now, you can also configure Redis with a maxmemory parameter, which prevents Redis from using any more memory (the default).

Newer versions of Redis have various policies when maxmemory is reached:

volatile-lru remove a key among the
ones with an expire set, trying to
remove keys not recently used.

volatile-ttl remove a key among the
ones with an expire set, trying to
remove keys with short remaining time
to live.

volatile-random remove a
random key among the ones with an
expire set.

allkeys-lru like
volatile-lru, but will remove every
kind of key, both normal keys or keys
with an expire set.

allkeys-random
like volatile-random, but will remove
every kind of keys, both normal keys
and keys with an expire set.

If you pick a policy that only removes keys with an EXPIRE set, then when Redis runs out of memory, it looks like the program just aborts the malloc() operation. That is, if you try to store more data, the operation just fails miserably.

Some links for more info (since you shouldn't just take my word for it):

Another way to use Redis as a cache is
the maxmemory directive, a feature
that allows specifying a maximum
amount of memory to use. When new data
is added to the server, and the memory
limit was already reached, the server
will remove some old data deleting a
volatile key, that is, a key with an
EXPIRE (a timeout) set, even if the
key is still far from expiring
automatically.

Also, Redis 2.0 has a VM mode where all keys must fit in memory, but the values for the rarely used keys can be on disk:

# Don't use more memory than the specified amount of bytes.
# When the memory limit is reached Redis will try to remove keys
# according to the eviction policy selected (see maxmemory-policy).
#
# If Redis can't remove keys according to the policy, or if the policy is
# set to 'noeviction', Redis will start to reply with errors to commands
# that would use more memory, like SET, LPUSH, and so on, and will continue
# to reply to read-only commands like GET.
#
# This option is usually useful when using Redis as an LRU cache, or to set
# a hard memory limit for an instance (using the 'noeviction' policy).
#
# WARNING: If you have slaves attached to an instance with maxmemory on,
# the size of the output buffers needed to feed the slaves are subtracted
# from the used memory count, so that network problems / resyncs will
# not trigger a loop where keys are evicted, and in turn the output
# buffer of slaves is full with DELs of keys evicted triggering the deletion
# of more keys, and so forth until the database is completely emptied.
#
# In short... if you have slaves attached it is suggested that you set a lower
# limit for maxmemory so that there is some free RAM on the system for slave
# output buffers (but this is not needed if the policy is 'noeviction').
#
# maxmemory <bytes>
# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory
# is reached. You can select among five behaviors:
#
# volatile-lru -> remove the key with an expire set using an LRU algorithm
# allkeys-lru -> remove any key according to the LRU algorithm
# volatile-random -> remove a random key with an expire set
# allkeys-random -> remove a random key, any key
# volatile-ttl -> remove the key with the nearest expire time (minor TTL)
# noeviction -> don't expire at all, just return an error on write operations
#
# Note: with any of the above policies, Redis will return an error on write
# operations, when there are no suitable keys for eviction.
#
# At the date of writing these commands are: set setnx setex append
# incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd
# sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby
# zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby
# getset mset msetnx exec sort
#
# The default is:
#
# maxmemory-policy volatile-lru

I recently experienced a no-free-memory situation and my application ground to a halt (writes not possible, reads were possible), running PHP scripts stopped dead in their tracks mid-way and had to be kill -9'd manually (even after memory was made available).

I assumed data loss (or data inconsistency) had occurred so I did a flushdb and restored from backups. Lesson learned? Backups are your friend.