Detailed explanation of Redis' expiration strategy, memory elimination strategy and LRU algorithm

Technical account full of useful information: This article has been included in github, welcome to star/fork: https://github.com/Wasabi1234/Java-Interview-Tutorial

1 Set a key with expiration time

expire key seconds
时间复杂度:O(1)

The set keyexpiration time. After timeout, it will be automatically deleted key. In Redis terminology a keyrelevant timeout is volatile.

After timeout, keyit will only be cleared when DEL, SET, or GETSET is executed. This means that conceptually all keyoperations that change without replacing with a new value will keep the timeout unchanged. For example, using INCRto increment the value of a key, performing a LPUSHpush of a new value into a list, or using to HSETchange a hash fieldwill keep the timeout unchanged.

  • The timeout can be cleared using PERSISTthe command to make it a permanentkey
  • If modified keyby RENAMEthe command, the related timeout period will be transferred to the newkey
  • If keyit is RENAMEmodified by the command, for example, it originally existed Key_A, and then the command is called RENAME Key_B Key_A, then regardless of whether Key_Ait is permanent or set to timeout, it will be Key_Boverwritten by the validity period status.

Note that calling EXPIRE/PEXPIRE with a non-positive timeout or EXPIREAT/PEXPIREAT with a time in the past will cause the key to be deleted rather than expired (thus, the key event emitted will be del, not expired).

1.1 Refresh expiration time

For keyexecution EXPIREoperations that already have an expiration time, their expiration time will be updated. There are many applications with this business scenario, such as session recording.

1.2 Differences between Redis and 2.1.3

In Redis versions prior to 2.1.3, changing a key with an expired set using the command that changes its value had the effect of completely deleting the key. This semantics is required due to limitations in the now-fixed replication layer.

EXPIRE will return 0 and will not change the timeout for keys with a timeout set.

1.3 Return value

  • 1If the expiration time is successfully set.
  • 0If keyit does not exist or the expiration time cannot be set.

1.4 Example

Suppose there is a Web service that is interested in the latest N pages that the user has recently visited, so that each adjacent page view is no more than 60 seconds after the previous page. Conceptually, think of this set of page views as a navigation session for the user, which might contain interesting information about the products they are currently looking for so that you can recommend related products.

This pattern can be easily modeled in Redis using the following strategy: Every time the user executes a page view, you call the following command:

MULTI
RPUSH pagewviews.user:<userid> http://.....
EXPIRE pagewviews.user:<userid> 60
EXEC

If the user is idle for more than 60 seconds, the key is deleted and only subsequent page views that differ by less than 60 seconds are recorded. This mode is easily modified to use INCR instead of using RPUSH's list.

1.5 Key with expiration time

Normally, Redis keys are created without a time-to-live associated with them. The key will persist unless the user deletes it explicitly (such as the DEL command). The EXPIRE family of commands can associate an expired item with a given key, at the expense of additional memory used by that key. When a key has an expiration set, Redis will ensure that the key is deleted when the specified time has passed. You can use the EXPIRE and PERSIST commands (or other strict commands) to update or completely delete critical times to live.

1.6 Expiration accuracy

In Redis 2.4, expiration may not be exact and may be between 0 and 1 second. Since Redis 2.6, the expiration error ranges from 0 to 1 milliseconds.

1.7 Expiration and persistence

The key for expiration information is stored as an absolute Unix timestamp (milliseconds for Redis version 2.6 or later). This means that time is flowing even when the Redis instance is not active. For expiration to work well, the computer time must be stabilized. If you move an RDB file between two machines that have large desyncs in their clocks, interesting things may happen (such as loading with all expired keys). Even when running an instance, the computer clock is always checked, for example if you set a key to 1000 seconds and then set the computer time 2000 seconds in the future, the key will expire immediately instead of lasting 1000 seconds.

2 How to expire key in Redis

There are two ways to expire keys: passive way - lazy deletion, active way - periodic deletion.

2.1 Lazy deletion

When the client tries to access the key, the key will expire passively, that is, Redis will check whether the key has an expiration time set, and if it expires, it will be deleted and nothing will be returned. Note that it is not that the key will be automatically deleted when it expires, but when querying the key, Redis lazily checks whether to delete it. This is similar to spring's delayed initialization.

Of course, this is not enough because there are expired keys that will never be accessed again. These keys should expire anyway, so periodically Redis randomly tests a few keys between keys with an expired set. All expired keys will be deleted from the key space.

2.2 Regular deletion

Specifically, the following Redis 10 times per second:

  1. Test 20 random keys with expiration
  2. Delete all expired keys found
  3. If more than 25% of keys have expired, start over from step 1

This is a trivially probabilistic algorithm that basically assumes our sample is representative of the entire key space and continues to expire until the percentage of keys that are likely to expire falls below 25%. This means that at any given moment, the maximum amount of expired keys using memory is equal to the maximum number of write operations/second divided by 4.

2.3 How to handle expiration in replication links and AOF files

In order to obtain correct behavior without sacrificing consistency, the DEL operation will simultaneously synthesize and obtain all attached slave nodes in the AOF file when the key expires. In this way, the expiration processing process is concentrated on the master node, and there is no possibility of consistency errors.

However, while slaves connected to the master will not independently expire the key (but will wait for the DEL from the master), they will still use the existing expired full state in the data set, so when the slave is selected as master, it will Ability to expire keys independently and fully act as master.

However, you did not check many expired keys in time and missed them by regularly deleting them. A large number of expired keys accumulate in memory and Redis memory is exhausted!

Therefore, a memory elimination mechanism is also needed!

3 memory elimination

3.1 Memory elimination strategy

noeviction (Redis default policy)

Write requests will not continue to be serviced (DEL requests can continue to be serviced), and read requests can continue. This can ensure that data will not be lost, but it will make online business unsustainable.

  • config.c
createEnumConfig("maxmemory-policy", NULL, 
	MODIFIABLE_CONFIG, maxmemory_policy_enum, 
		server.maxmemory_policy, 
			MAXMEMORY_NO_EVICTION, NULL, NULL),

allkeys-random

When the memory is insufficient to accommodate newly written data, a key is randomly removed from the key space. Why is it random? At least the least recently used key is deleted.

allkeys-lru(Least Recently Used)

When the memory is insufficient to accommodate newly written data, in the key space, the least recently used key is removed, and keys without an expiration time are also eliminated.

allkeys-lfu(Least Frequently Used)

The key to LRU is to look at the length of time from when the page was last used until scheduling occurs , while the key to LFU is to look at the frequency of page use within a certain period of time .

volatile-lru

Try to eliminate keys with an expiration time set, and the least used keys will be eliminated first. Keys with no expiration time set will not be eliminated, which ensures that data that needs to be persisted will not be suddenly lost. Different from allkey-lru, this strategy eliminates only expired key sets.

volatile-lfu

volatile-random

The eliminated key is a random key in the expired key set.

volatile-ttl

The elimination strategy is not LRU, but the value of the key's remaining life ttl. The smaller the ttl, the priority it will be eliminated.

The volatile-xxx policy will only eliminate keys with expiration time, and the allkeys-xxx policy will eliminate all keys.

  • If you only use Redis for caching, you should use allkeys-xxx. The client does not need to carry the expiration time when writing the cache.
  • If you also want to use the persistence function of Redis at the same time, then use the volatile-xxx strategy, so that you can retain keys without set expiration time. They are permanent keys and will not be eliminated by the LRU algorithm.

3.2 Handwritten LRU

Indeed, this question is sometimes asked, because if some candidates really pass five levels and win six generals, and have answered the previous questions very well, then in fact, asking them to write about the LRU algorithm can test their coding skills.

You can hand-write the original LRU algorithm on the spot, but the amount of code is too large and unrealistic.

public class LRUCache<K, V> extends LinkedHashMap<K, V> {
    
private final int CACHE_SIZE;

    // 这里就是传递进来最多能缓存多少数据
    public LRUCache(int cacheSize) {
    	//  true指linkedhashmap将元素按访问顺序排序
        super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
        CACHE_SIZE = cacheSize;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
    	 // 当KV数据量大于指定缓存个数时,就自动删除最老数据
        return size() > CACHE_SIZE;
    }

}

reference

OpenAI opens ChatGPT to all users for free. Voice programmers tampered with ETC balances and embezzled more than 2.6 million yuan a year. Spring Boot 3.2.0 was officially released. Google employees criticized the big boss after leaving the company. He was deeply involved in the Flutter project and formulated HTML-related standards. Microsoft Copilot Web AI will be Officially launched on December 1st, supporting Chinese Microsoft's open source Terminal Chat Rust Web framework Rocket releases v0.5: supports asynchronous, SSE, WebSockets, etc. The father of Redis implements the Telegram Bot framework using pure C language code . If you are an open source project maintainer, encounter How far can you endure this kind of response? PHP 8.3 GA
{{o.name}}
{{m.name}}

おすすめ

転載: my.oschina.net/u/3494859/blog/4548537