This article brings you how Redis solves the problem of cache inconsistency and how the data inconsistency between the cache and the database occurs. Let’s take a look at it together. I hope it will be helpful to everyone. .
Recommended study: Redis learning tutorial
First of all, we have to understand what "data consistency" specifically means. In fact, the "consistency" here includes two situations:
If these two situations are not met, it is a data inconsistency problem between the cache and the database. However, when the cache read and write modes are different, the occurrence of cache data inconsistency is different, and our response methods will also be different. Therefore, we first understand the cache inconsistencies in different modes according to the cache read and write modes. Condition. We can divide cache into read-write cache and read-only cache.
For read-write cache, if you want to add, delete or modify data, you need to do it in the cache. At the same time, you must decide whether to write it back to the database synchronously based on the write-back strategy adopted.
Synchronous direct write strategy: When writing the cache, the database is also written synchronously, and the data in the cache and the database are consistent;
Asynchronous write-back strategy: When writing the cache, the database is not written synchronously until the data is written from When eliminated from the cache, it is written back to the database. When using this strategy, if the data has not been written back to the database, the cache will fail, and at this time, the database will not have the latest data.
So, for read-write cache, if you want to ensure that the data in the cache and the database are consistent, you must adopt a synchronous direct write strategy. However, it should be noted that if you adopt this strategy, you need to update the cache and database at the same time. Therefore, we need to use transaction mechanisms in business applications to ensure that cache and database updates are atomic. That is to say, they are either updated together or neither is updated, an error message is returned, and retry is performed. Otherwise, we cannot achieve synchronous direct writing.
Of course, in some scenarios, our requirements for data consistency may not be so high. For example, if we cache non-critical attributes of e-commerce products or the creation or modification time of short videos, then we An asynchronous writeback strategy can be used.
Let’s talk about read-only caching. For read-only cache, if there is new data, it will be written directly to the database; when there is data deletion, the data in the read-only cache needs to be marked as invalid. In this way, when the application subsequently accesses these added, deleted, or modified data, a cache miss will occur because there is no corresponding data in the cache. At this time, the application reads the data from the database into the cache, so that when the data is accessed later, it can be read directly from the cache.
Next, take Tomcat writing and deleting data to MySQL as an example to explain to you how the data addition, deletion and modification operations are performed, as shown in the following figure:
As can be seen from the figure, applications running on Tomcat, whether adding (Insert operation), modifying (Update operation), or deleting (Delete operation) data X, will directly add, modify and delete data in the database. Of course, if the application performs a modification or deletion operation, the cached data X will also be deleted.
So, will there be data inconsistency in this process? Considering that the situations of adding data and deleting data are different, we look at them separately.
We assume that the application first deletes the cache and then updates the database. If the cache is deleted successfully but the database update fails, then when the application accesses the data again, there will be no data in the cache, and a cache miss will occur. Then, the application accesses the database again, but the value in the database is the old value, and the application accesses the old value.
Let me give you an example. You can first look at the picture below
The application wants to update the value of data X from 10 to 3. It first deletes the cache value of X in the Redis cache, but the update to the database fails. If there are other concurrent requests to access
You may ask, if we update the database first and then delete the value in the cache, can this problem be solved? Let’s analyze it again.
If the application completes the database update first, but fails when deleting the cache, then the value in the database is the new value and the value in the cache is the old value, which is definitely inconsistent. At this time, if there are other concurrent requests to access the data, according to the normal cache access process, the cache will be queried first, but at this time, the old value will be read.
Let me explain it with the help of an example.
The application wants to update the value of data X from 10 to 3. It first successfully updates the database, and then deletes the cache of X in the Redis cache, but this operation failed. , at this time, the new value of X in the database is 3, and the cached value of X in Redis is 10, which is definitely inconsistent. If another client happens to send a request to access X at this time, it will first query in Redis. The client will find a cache hit, but the old value 10 will be read.
Okay, here we can see that in the process of updating the database and deleting cached values, no matter which of the two operations is performed first or later, as long as one operation fails, it will Causes the client to read old values. I drew the table below to summarize the two situations just mentioned.
We know the cause of the problem, but how to solve it?
First of all, let me introduce you to a method: the retry mechanism.
Specifically, you can temporarily store the cached value to be deleted or the database value to be updated in the message queue (for example, using the Kafka message queue). When an application fails to successfully delete cached values or update database values, it can reread the values from the message queue and delete or update them again.
If we can successfully delete or update, we will remove these values from the message queue to avoid repeated operations. At this time, we can also ensure that the database and cached data are consistent. Otherwise, we need to try again. If the retry exceeds a certain number of times and still fails, we need to send an error message to the business layer.
The following figure shows when updating the database first and then deleting the cache value. If the cache deletion fails, you can take a look at the situation where the deletion is successful after retrying.
What I just talked about is the situation where one of the operations fails during the process of updating the database and deleting cached values. In fact, even if these two operations are executed for the first time None of them failed. When there are a large number of concurrent requests, the application may still read inconsistent data.
Similarly, we divide it into two situations according to different deletion and update orders. In both cases, our solutions are also different.
Assume that after thread A deletes the cache value, thread B starts to read the data before it has time to update the database (for example, there is a network delay). Then at this time, thread B will find that the cache is missing. You can only read from the database. This will bring about two problems:
Wait until thread B reads the data from the database and updates the cache, then thread A starts to update the database. At this time, the data in the cache is the old value, while the data in the database is the latest value. The two are inconsistent.
I use a table to summarize this situation.
What should we do? Let me provide you with a solution.
After thread A updates the database value, we can let it sleep for a short period of time and then perform a cache deletion operation.
The reason why the sleep period is added is to allow thread B to read data from the database first, then write the missing data to the cache, and then thread A deletes it. Therefore, the time for thread A to sleep needs to be greater than the time for thread B to read data and then write it to the cache. How to determine this time? It is recommended that you count the operation time of threads reading data and writing cache when the business program is running, and make an estimate based on this.
In this way, when other threads read data, they will find that the cache is missing, so they will read the latest value from the database. Because this solution will delay the deletion for a period of time after deleting the cached value for the first time, we also call it "delayed double deletion".
The following pseudo code is an example of the "delayed double deletion" scheme, you can take a look.
redis.delKey(X) db.update(X) Thread.sleep(N) redis.delKey(X)
Scenario 2: Update the database value first, and then delete the cache value.
If thread A deletes the value in the database, but before it has time to delete the cache value, thread B starts to read the data. At this time, when thread B queries the cache, it finds a cache hit. The old value will be read directly from the cache. However, in this case, if there are not many concurrent requests from other threads to read the cache, then there will not be many requests to read the old value. Also, Thread A will typically delete the cached value very quickly, so that when another thread reads again, a cache miss will occur and the latest value will be read from the database. Therefore, this situation has less impact on the business.
I will draw another table to show you the situation of updating the database first and then deleting the cached value.
Okay, here we have learned that the data inconsistency between the cache and the database is generally caused by two reasons. I have provided you with the corresponding solution.
Recommended learning: Redis video tutorial
The above is the detailed content of How does redis solve the problem of cache inconsistency?. For more information, please follow other related articles on the PHP Chinese website!