{
  "id": "eviction",
  "title": "Key eviction",
  "url": "https://redis.io/docs/latest/develop/reference/eviction/",
  "summary": "Overview of Redis key eviction policies (LRU, LFU, etc.)",
  "tags": [
    "docs",
    "develop",
    "stack",
    "oss",
    "rs",
    "rc",
    "oss",
    "kubernetes",
    "clients"
  ],
  "last_updated": "2026-04-01T08:10:08-05:00",
  "page_type": "content",
  "content_hash": "8e8c5a6175e51fb33918858dd439a1e73e06736d7a6258232311a2e1c1f77bb3",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "Redis is commonly used as a cache to speed up read accesses to a slower server\nor database. Since cache entries are copies of persistently-stored data, it\nis usually safe to evict them when the cache runs out of memory (they can be\ncached again in the future if necessary).\n\nRedis lets you specify an eviction policy to evict keys automatically\nwhen the size of the cache exceeds a set memory limit. Whenever a client\nruns a new command that adds more data to the cache, Redis checks the memory usage.\nIf it is greater than the limit, Redis evicts keys according to the chosen\neviction policy until the total memory used is back below the limit.\n\nNote that when a command adds a lot of data to the cache (for example, a big set\nintersection stored into a new key), this might temporarily exceed the limit by\na large amount.\n\nThe sections below explain how to [configure the memory limit](#maxmem) for the cache\nand also describe the available [eviction policies](#eviction-policies) and when to\nuse them."
    },
    {
      "id": "using-the-maxmemory-configuration-directive-maxmem",
      "title": "Using the `maxmemory` configuration directive {#maxmem}",
      "role": "content",
      "text": "The `maxmemory` configuration directive specifies\nthe maximum amount of memory to use for the cache data. You can\nset `maxmemory` with the [`redis.conf`](https://github.com/redis/redis/blob/7.4.0/redis.conf)\nfile at startup time. For example, to configure a memory limit of 100 megabytes,\nyou can use the following directive inside `redis.conf`:\n\n[code example]\n\nYou can also use [`CONFIG SET`]() to\nset `maxmemory` at runtime using [`redis-cli`]():\n\n[code example]\n\nSet `maxmemory` to zero to specify that you don't want to limit the memory\nfor the dataset. This is the default behavior for 64-bit systems, while 32-bit\nsystems use an implicit memory limit of 3GB.\n\nWhen the size of your cache exceeds the limit set by `maxmemory`, Redis will\nenforce your chosen [eviction policy](#eviction-policies) to prevent any\nfurther growth of the cache."
    },
    {
      "id": "setting-maxmemory-for-a-replicated-or-persisted-instance",
      "title": "Setting `maxmemory` for a replicated or persisted instance",
      "role": "configuration",
      "text": "If you are using\n[replication]()\nor [persistence]()\nfor a server, Redis will use some RAM as a buffer to store the set of updates waiting\nto be written to the replicas or AOF files.\nThe memory used by this buffer is not included in the total that\nis compared to `maxmemory` to see if eviction is required.\n\nThis is because the key evictions themselves generate updates that must be added\nto the buffer. If the updates were counted among the used\nmemory then in some circumstances, the memory saved by\nevicting keys would be immediately used up by the update data added to the buffer.\nThis, in turn, would trigger even more evictions and the resulting feedback loop\ncould evict many items from the cache unnecessarily.\n\nIf you are using replication or persistence, we recommend that you set\n`maxmemory` to leave a little RAM free to store the buffers. Note that this is not\nnecessary for the `noeviction` policy (see [the section below](#eviction-policies)\nfor more information about eviction policies).\n\nThe [`INFO`]() command returns a\n`mem_not_counted_for_evict` value in the `memory` section (you can use\nthe `INFO memory` option to see just this section). This is the amount of\nmemory currently used by the buffers. Although the exact amount will vary,\nyou can use it to estimate how much to subtract from the total available RAM\nbefore setting `maxmemory`."
    },
    {
      "id": "eviction-policies",
      "title": "Eviction policies",
      "role": "content",
      "text": "Use the `maxmemory-policy` configuration directive to select the eviction\npolicy you want to use when the limit set by `maxmemory` is reached.\n\nThe following policies are available:\n\n-   `noeviction`: Keys are not evicted but the server will return an error\n    when you try to execute commands that cache new data. If your database uses replication\n    then this condition only applies to the primary database. Note that commands that only\n    read existing data still work as normal.\n-   `allkeys-lru`: Evict the [least recently used](#apx-lru) (LRU) keys.\n-   `allkeys-lrm`: Evict the [least recently modified](#lrm-eviction) (LRM) keys.\n-   `allkeys-lfu`: Evict the [least frequently used](#lfu-eviction) (LFU) keys.\n-   `allkeys-random`: Evict keys at random.\n-   `volatile-lru`: Evict the least recently used keys that have an associated expiration (TTL).\n-   `volatile-lrm`: Evict the least recently modified keys that have an associated expiration (TTL).\n-   `volatile-lfu`: Evict the least frequently used keys that have an associated expiration (TTL).\n-   `volatile-random`: Evicts random keys that have an associated expiration (TTL).\n-   `volatile-ttl`: Evict keys with an associated expiration (TTL) that have the shortest remaining TTL value.\n\nThe `volatile-xxx` policies behave like `noeviction` if no keys have an associated expiration.\n\nYou should choose an eviction policy that fits the way your app\naccesses keys. You may be able to predict the access pattern in advance\nbut you can also use information from the `INFO` command at runtime to\ncheck or improve your choice of policy (see\n[Using the `INFO` command](#using-the-info-command) below for more information).\n\nAs a rule of thumb:\n\n-   Use `allkeys-lru` when you expect that a subset of elements will be accessed far\n    more often than the rest. This is a very common case according to the\n    [Pareto principle](https://en.wikipedia.org/wiki/Pareto_principle), so\n    `allkeys-lru` is a good default option if you have no reason to prefer any others.\n-   Use `allkeys-lrm` when you want to preserve frequently read data but evict data\n    that hasn't been modified recently. This is useful for read-heavy workloads where\n    you want to distinguish between data that's actively being updated versus data\n    that's only being read.\n-   Use `allkeys-random` when you expect all keys to be accessed with roughly equal\n    frequency. An example of this is when your app reads data items in a repeating cycle.\n-   Use `volatile-ttl` if your code can estimate which keys are good candidates for eviction\n    and assign short TTLs to them. Note also that if you make good use of\n    key expiration, then you are less likely to run into the cache memory limit because keys\n    will often expire before they need to be evicted.\n\nThe `volatile-lru`, `volatile-lrm`, and `volatile-random` policies are mainly useful when you want to use\na single Redis instance for both caching and for a set of persistent keys. However,\nyou should consider running two separate Redis instances in a case like this, if possible.\n\nAlso note that setting an `expire` value for a key costs memory, so a\npolicy like `allkeys-lru` is more memory efficient since it doesn't need an\n`expire` value to operate."
    },
    {
      "id": "using-the-info-command",
      "title": "Using the `INFO` command",
      "role": "content",
      "text": "The [`INFO`]() command provides several pieces\nof data that are useful for checking the performance of your cache. In particular,\nthe `INFO stats` section includes two important entries, `keyspace_hits` (the number of\ntimes keys were successfully found in the cache) and `keyspace_misses` (the number\nof times a key was requested but was not in the cache). The calculation below gives\nthe percentage of attempted accesses that were satisfied from the cache:\n\n[code example]\n\nCheck that this is roughly equal to what you would expect for your app\n(naturally, a higher percentage indicates better cache performance).\n\n When the [`EXISTS`]()\ncommand reports that a key is absent then this is counted as a keyspace miss.\n\n\nIf the percentage of hits is lower than expected, then this might\nmean you are not using the best eviction policy. For example, if\nyou believe that a small subset of \"hot\" data (that will easily fit into the\ncache) should account for about 75% of accesses, you could reasonably\nexpect the percentage of keyspace hits to be around 75%. If the actual\npercentage is lower, check the value of `evicted_keys` (also returned by\n`INFO stats`). A high proportion of evictions would suggest that the\nwrong keys are being evicted too often by your chosen policy\n(so `allkeys-lru` might be a good option here). If the\nvalue of `evicted_keys` is low and you are using key expiration, check\n`expired_keys` to see how many keys have expired. If this number is high,\nyou might be using a TTL that is too low or you are choosing the wrong\nkeys to expire and this is causing keys to disappear from the cache\nbefore they should.\n\nOther useful pieces of information returned by `INFO` include:\n\n-   `used_memory_dataset`: (`memory` section) The amount of memory used for\n    cached data. If this is greater than `maxmemory`, then the difference\n    is the amount by which `maxmemory` has been exceeded.\n-   `current_eviction_exceeded_time`: (`stats` section) The time since\n    the cache last started to exceed `maxmemory`.\n-   `commandstats` section: Among other things, this reports the number of\n    times each command issued to the server has been rejected. If you are\n    using `noeviction` or one of the `volatile_xxx` policies, you can use\n    this to find which commands are being stopped by the `maxmemory` limit\n    and how often it is happening."
    },
    {
      "id": "approximated-lru-algorithm-apx-lru",
      "title": "Approximated LRU algorithm {#apx-lru}",
      "role": "content",
      "text": "The Redis LRU algorithm uses an approximation of the least recently used\nkeys rather than calculating them exactly. It samples a small number of keys\nat random and then evicts the ones with the longest time since last access.\n\nFrom Redis 3.0 onwards, the algorithm also tracks a pool of good\ncandidates for eviction. This improves the performance of the algorithm, making\nit a close approximation to a true LRU algorithm.\n\n(Redis Open Source only) You can tune the performance of the algorithm by changing the number of samples to check\nbefore every eviction with the `maxmemory-samples` configuration directive:\n\n[code example]\n\nSee these pages for information on eviction policies in: (1) [Redis Software]() and (2) [Redis Cloud]().\n\nThe reason Redis does not use a true LRU implementation is because it\ncosts more memory. However, the approximation is virtually equivalent for an\napplication using Redis. This figure compares\nthe LRU approximation used by Redis with true LRU.\n\n![LRU comparison](lru_comparison.png)\n\nThe test to generate the above graphs filled a Redis server with a given number of keys. The keys were accessed from the first to the last. The first keys are the best candidates for eviction using an LRU algorithm. Later more 50% of keys are added, in order to force half of the old keys to be evicted.\n\nYou can see three kind of dots in the graphs, forming three distinct bands.\n\n* The light gray band are objects that were evicted.\n* The gray band are objects that were not evicted.\n* The green band are objects that were added.\n\nIn a theoretical LRU implementation we expect that, among the old keys, the first half will be expired. The Redis LRU algorithm will instead only *probabilistically* expire the older keys.\n\nAs you can see Redis 3.0 does a better job with 5 samples compared to Redis 2.8, however most objects that are among the latest accessed are still retained by Redis 2.8. Using a sample size of 10 in Redis 3.0 the approximation is very close to the theoretical performance of Redis 3.0.\n\nNote that LRU is just a model to predict how likely a given key will be accessed in the future. Moreover, if your data access pattern closely\nresembles the power law, most of the accesses will be in the set of keys\nthe LRU approximated algorithm can handle well.\n\nIn simulations we found that using a power law access pattern, the difference between true LRU and Redis approximation were minimal or non-existent.\n\nHowever you can raise the sample size to 10 at the cost of some additional CPU\nusage to closely approximate true LRU, and check if this makes a\ndifference in your cache misses rate.\n\nTo experiment in production with different values for the sample size by using\nthe `CONFIG SET maxmemory-samples <count>` command, is very simple."
    },
    {
      "id": "lfu-eviction",
      "title": "LFU eviction",
      "role": "content",
      "text": "Starting with Redis 4.0, the [Least Frequently Used eviction mode](http://antirez.com/news/109) is available. This mode may work better (provide a better\nhits/misses ratio) in certain cases. In LFU mode, Redis will try to track\nthe frequency of access of items, so the ones used rarely are evicted. This means\nthe keys used often have a higher chance of remaining in memory.\n\nTo configure the LFU mode, the following policies are available:\n\n* `volatile-lfu` Evict using approximated LFU among the keys with an expire set.\n* `allkeys-lfu` Evict any key using approximated LFU.\n\nLFU is approximated like LRU: it uses a probabilistic counter, called a [Morris counter](https://en.wikipedia.org/wiki/Approximate_counting_algorithm) to estimate the object access frequency using just a few bits per object, combined with a decay period so that the counter is reduced over time. At some point we no longer want to consider keys as frequently accessed, even if they were in the past, so that the algorithm can adapt to a shift in the access pattern.\n\nThat information is sampled similarly to what happens for LRU (as explained in the previous section of this documentation) to select a candidate for eviction.\n\nHowever unlike LRU, LFU has certain tunable parameters: for example, how fast\nshould a frequent item lower in rank if it gets no longer accessed? It is also possible to tune the Morris counters range to better adapt the algorithm to specific use cases.\n\nBy default Redis is configured to:\n\n* Saturate the counter at, around, one million requests.\n* Decay the counter every one minute.\n\nThose should be reasonable values and were tested experimentally, but the user may want to play with these configuration settings to pick optimal values.\n\nInstructions about how to tune these parameters can be found inside the example `redis.conf` file in the source distribution. Briefly, they are:\n\n[code example]\n\nThe decay time is the obvious one, it is the amount of minutes a counter should be decayed, when sampled and found to be older than that value. A special value of `0` means: we will never decay the counter.\n\nThe counter *logarithm factor* changes how many hits are needed to saturate the frequency counter, which is just in the range 0-255. The higher the factor, the more accesses are needed to reach the maximum. The lower the factor, the better is the resolution of the counter for low accesses, according to the following table:\n\n[code example]\n\nSo basically the factor is a trade off between better distinguishing items with low accesses VS distinguishing items with high accesses. More information is available in the example `redis.conf` file."
    },
    {
      "id": "lrm-eviction-lrm-eviction",
      "title": "LRM eviction {#lrm-eviction}",
      "role": "content",
      "text": "Starting with Redis 8.6, the Least Recently Modified (LRM) eviction policy is available. LRM is similar to LRU but only updates the timestamp on write operations, not read operations. This makes it useful for evicting keys that haven't been modified recently, regardless of how frequently they are read.\n\nThe key difference between LRU and LRM is:\n\n- **LRU (Least Recently Used)**: Updates the access timestamp on both read and write operations\n- **LRM (Least Recently Modified)**: Updates the access timestamp only on write operations\n\nThis distinction makes LRM particularly useful in scenarios where:\n\n- Your application has a clear distinction between read-heavy and write-heavy workloads\n- You want to evict stale data that hasn't been updated, regardless of read activity\n\nTo configure LRM eviction, the following policies are available:\n\n* `volatile-lrm` Evict using LRM among the keys with an an associated expiration (TTL).\n* `allkeys-lrm` Evict any key using LRM.\n\nLike LRU, LRM uses an approximation algorithm that samples a small number of keys at random and evicts the ones with the longest time since last modification. The same `maxmemory-samples` configuration directive that affects LRU performance also applies to LRM."
    }
  ],
  "examples": [
    {
      "id": "using-the-maxmemory-configuration-directive-maxmem-ex0",
      "language": "plaintext",
      "code": "maxmemory 100mb",
      "section_id": "using-the-maxmemory-configuration-directive-maxmem"
    },
    {
      "id": "using-the-maxmemory-configuration-directive-maxmem-ex1",
      "language": "bash",
      "code": "> CONFIG SET maxmemory 100mb",
      "section_id": "using-the-maxmemory-configuration-directive-maxmem"
    },
    {
      "id": "using-the-info-command-ex0",
      "language": "plaintext",
      "code": "keyspace_hits / (keyspace_hits + keyspace_misses) * 100",
      "section_id": "using-the-info-command"
    },
    {
      "id": "approximated-lru-algorithm-apx-lru-ex0",
      "language": "plaintext",
      "code": "maxmemory-samples 5",
      "section_id": "approximated-lru-algorithm-apx-lru"
    },
    {
      "id": "lfu-eviction-ex0",
      "language": "plaintext",
      "code": "lfu-log-factor 10\nlfu-decay-time 1",
      "section_id": "lfu-eviction"
    },
    {
      "id": "lfu-eviction-ex1",
      "language": "plaintext",
      "code": "+--------+------------+------------+------------+------------+------------+\n| factor | 100 hits   | 1000 hits  | 100K hits  | 1M hits    | 10M hits   |\n+--------+------------+------------+------------+------------+------------+\n| 0      | 104        | 255        | 255        | 255        | 255        |\n+--------+------------+------------+------------+------------+------------+\n| 1      | 18         | 49         | 255        | 255        | 255        |\n+--------+------------+------------+------------+------------+------------+\n| 10     | 10         | 18         | 142        | 255        | 255        |\n+--------+------------+------------+------------+------------+------------+\n| 100    | 8          | 11         | 49         | 143        | 255        |\n+--------+------------+------------+------------+------------+------------+",
      "section_id": "lfu-eviction"
    }
  ]
}
