The story of Redis cache failure starts with the EXPIRE command. EXPIRE allows users to specify a timeout for a key. When this time is exceeded, the value corresponding to the key will be cleared. This article mainly analyzes the basis of the Redis source code. The website above considers issues related to Redis cache failure from the perspective of a Redis designer.
Redis cache invalidation mechanism
The Redis cache invalidation mechanism is designed to deal with a very common scenario in caching applications. , let’s talk about a scenario:
In order to reduce the pressure on the back-end database, we happily used the Redis service to load data that does not change very frequently from the DB load and put it into the cache. Therefore, within a period of time we You can get data directly from the cache, but we hope that after a period of time, we will load the current data from the DB into the cache again. How to do this?
The question has been raised, how to solve this problem? Well, we are very familiar with the language tools at hand, and we firmly believe that we can quickly write such a piece of logic: we record the last time we loaded data from the db, and then determine whether the time has expired every time we respond to the service. Do you want to reload from db...? Of course, this method is also possible. However, when we checked the Redis command document, we found that we did something that we did not need to do. Redis itself provides this mechanism. We can easily do this with the help of the EXPIRE command:
EXPIRE key 30
The above command sets an expiration time of 30 seconds for the key. Beyond this time, we should not be able to access this value. So far we have roughly understood what the cache invalidation mechanism and cache invalidation mechanism are. Some application scenarios, let's continue to delve into this issue. How is the Redis cache invalidation mechanism implemented?
Delayed invalidation mechanism
Delayed invalidation mechanism means that when the client requests to operate a key, Redis will check the validity period of the key requested by the client. If Corresponding processing is performed only after the key expires. The delayed failure mechanism is also called the passive failure mechanism. Let’s take a look at the server-side execution stack for get request processing under the t_string component:
getCommand -> getGenericCommand -> lookupKeyReadOrReply -> lookupKeyRead -> expireIfNeeded
The key point is expireIfNeed. Redis will determine whether the value associated with the key is invalid before the get operation on the key. Insert it here first. A small episode, let's take a look at what the actual place where values are stored in Redis looks like:
typedef struct redisDb { dict *dict; /* The keyspace for this DB */ dict *expires; /* Timeout of keys with a timeout set */ dict *blocking_keys; /* Keys with clients waiting for data (BLPOP) */ dict *ready_keys; /* Blocked keys that received a PUSH */ dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */ int id; long long avg_ttl; /* Average TTL, just for stats */} redisDb;
The above is a structure defined in Redis. dict is a dictionary implemented by Redis, that is, each DB It will include the five fields above. We only care about two dictionaries here, one is dict and one is expires:
dict is used to store normal data. For example, if we execute set key "hahaha", this The data is stored in dict.
expires is used to store keys associated with expiration time. For example, if we execute expire key 1 based on the above, a record will be added to expires at this time.
Looking back at the process of expireIfNeeded, it is roughly as follows:
Find the expiration time of the key from expires. If it does not exist, it means that the corresponding key does not have an expiration time set, and returns directly.
If it is a slave machine, it will be returned directly, because in order to ensure data consistency and simple implementation, Redis gives the initiative of cache invalidation to the Master machine, and the slave machine does not have the authority to invalidate the key.
If it is currently the Master machine and the key expires, the master will do two important things: 1) Write the delete command to the AOF file. 2) Notify Slave that the current key is invalid and can be deleted.
Master deletes the value of key from the local dictionary.
Active invalidation mechanism
The active invalidation mechanism is also called the active invalidation mechanism, that is, the server regularly checks the invalid cache and performs corresponding operations if it fails.
We all know that Redis is single-threaded and event-driven. There is an EventLoop in Redis. EventLoop is responsible for processing two types of events:
One type is IO events. This type of event It is separated from the underlying multiplexer.
The first type is scheduled events, which are mainly used for the scheduled execution of a certain task.
It seems that the EventLoop function of Redis is roughly similar to that of Netty and JavaScript. On the one hand, it handles network I/O events, and on the other hand, it can also do some small tasks.
Why talk about the single-threaded model of Redis? Because the active failure mechanism logic of Redis is treated as a scheduled task to be executed by the main thread. The relevant code is as follows:
if(aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) { redisPanic("Can't create the serverCron time event."); exit(1); }
serverCron is this timing The function pointer of the task, adCreateTimeEvent registers the serverCron task to EventLoop and sets the initial execution time to 1 millisecond later. Next, everything we want to know is in serverCron. serverCron does a lot of things. We only care about the parts related to this article, that is, how cache invalidation is implemented. I think the call stack is relatively intuitive depending on what the code does:
aeProcessEvents ->processTimeEvents ->serverCron -> databasesCron -> activeExpireCycle -> activeExpireCycleTryExpire
EventLoop Through the processing of scheduled tasks, the execution of serverCron logic is triggered, and finally the logic of key expiration processing is executed. It is worth mentioning that activeExpireCycle logic can only be done by the master.
For more redis knowledge, please pay attention to the redis introductory tutorial column.
The above is the detailed content of Introduction to Redis cache invalidation mechanism. For more information, please follow other related articles on the PHP Chinese website!