A few years ago, I was reading a blog post about database cache consistency, so I didn’t think it was a good idea to talk about such a simple issue. This idea persisted for a long time until ONE day, when I saw more and more people talking about database cache consistency, I took a closer look at the blog and realized that database cache consistency is really not an easy problem. Today I’m also going to talk about databases, cache consistency.

The popular science

For those of you who may not be that skilled and have never been exposed to caches, I’m going to take a minute to explain what caches are, why they exist, and how databases and caches work together.

Database reading is a time-consuming operation. If you need to go to the database to read data every time, it will cause a certain pressure on the database, and the program performance will be relatively low, so you need to introduce cache.

Caching is one of the most important, effective, and simple ways to improve application performance.

After the cache is introduced, the read operation will be read in the cache first. If it does not hit the cache, it will read the database, and then put the read data into the cache. In this way, the next read operation can hit the cache.

Write operations, in addition to modifying the database, also need to delete the cache, because without deleting the cache, read operations will always read the old data in the cache.

Delete the cache first, then modify the database

The scheme is clearly flawed.

Two concurrent read and write operations:

  1. A write operation comes in first and deletes the cache;
  2. When the database is not updated by the write operation, a read request comes in, and the old data is fetched from the database.
  3. Write operations update the database;
  4. Read operations put old data in the cache.

Thus, the data in the database is inconsistent with the data in the cache. To better understand this process, here is an ugly picture:

It’s obviously not working, but is it really useless?

No, let’s imagine this scenario: a write request comes in and deletes the cache. At this time, the Redis server suddenly fails, or the network suddenly fails, causing the cache deletion to fail, throwing an exception, causing the program to not continue to modify the database operation. From the point of view of database and cache consistency, the consistency of database and cache is very good. The data stored in both is the same, although it is old data.

Modify the database first, then delete the cache

I believe that most of my friends are using this scheme. Before, I thought database and cache consistency was too simple to discuss, just because I thought this scheme was so perfect. But later, I gradually found that this scheme also had some problems.

When you look at the problem with the first one, you must think that this one has the same problem.

Two concurrent read and write operations without caching:

  1. When the read operation came first, it was found that there was no cache, so it went to the database to read the data. At this time, because of some reason, the data was not put into the cache in time.
  2. Write operations come in, modify the database, delete the cache;
  3. Read recovery, write old data to cache.

, thus causing the database cache are not consistent, but the probability is very low, because it requires in the absence of cache, concurrent operation, have to read and write in the general case, write the operation of the database is much slower than read database operations, in this case, and ensure that write cache read operation later than write delete cache will not appear this problem, So the problem should be negligible.

We don’t see the fatal problem of modifying the database first and then deleting the cache. Wait, let’s continue with the following scenario: A write operation came in, modify the database, but delete the cache, due to the Redis server problems, or network problems, resulting in the deletion of the cache failed, so the database is stored in the new data, but the cache is still old data, no problem with the database, cache inconsistent ah.

Double delete delay

As you can see, there are two problems with modifying the database and then deleting the cache. Although both problems are low probability, perfectionist programmers cannot allow such problems, so a third solution is introduced: delayed double delete.

Delayed dual deletion means that the cache is deleted first, the database is modified, and the cache is deleted again after a certain delay.

In this way, the above two problems can be alleviated to some extent. The first time to delete the cache is to check whether the cache service is available and whether there is a problem with the network. The second time is delayed for a certain amount of time, and the second time to delete the cache is to ensure that the read request is completed before the write request.

However, there are still some problems, such as the first time to delete the cache was successful, the second time to delete the cache failed, what should be done?

Memory queue

The above three methods all have certain problems:

  • Modify the database, delete the cache these two operations are coupled together, do not have a good single responsibility;
  • If the write operation is frequent, it may cause some pressure to Redis.
  • What if you fail to delete the cache?

In order to solve the above three problems, the fourth method is introduced: memory queue delete cache: Write operation only modifies the database and puts the Id of the data in the memory queue. In the background, a thread consumes the data in the memory queue and deletes the cache. If the cache deletion fails, it can retry several times.

This decouples database modification from cache deletion, and allows multiple attempts if the cache deletion fails. Since there is a thread in the background consuming the memory queue to delete the cache, rather than directly deleting the cache, there is a delay between modifying the database and deleting the cache, which should ensure that the read operation has completed.

But there are downsides to this:

  • Exponentially more complex applications need to maintain threads, queues, and consumers;
  • If the write operation is very frequent, the data in the queue may be consumed slowly. After the database is modified, the cache is deleted after a certain interval.

But there is no way. There is no perfect solution.

Third party queue

Generally speaking, the system is divided into foreground system and background system, foreground system is mainly read operation, background system only write operation.

For example, in the commodity center, the foreground is for users. When users open the commodity details page, they will get data from the cache. The background is for business personnel, who can modify the commodity information in the background system.

If it is a certain size of the company, the foreground system and the background system are certainly not on the same server, and is responsible for by different departments, so the memory queue is certainly not used, if the background system to modify the database, directly delete the cache, will happen the following story.

Xiaoming: What format is the key for the product details cache of your foreground system? Send me. Foreground system floret: Product:XXXXX. Xiaoming: Ok.

After a few days, floret find Xiao Ming.

Front desk system Floret: No. Why didn’t you remove the product details cache from the campaign? Xiaoming: Nani, how do I know you are two caches? Please send me the key format of the product details caches in the activity. Foreground system floret: Activity:Product:XXXX. Xiaoming: Ok.

After a few days, the development of the order system found Xiao Ming again. Order system Xiaoqiang: after you modify the product details, you also need to delete the product details cache in the order. Background system Xiaoming:…

After a few days, the development of advertising system found Xiao Ming again. Advertisement system Xiao Wang: After you modify the product details, you also need to delete the product details cache in the advertisement.

Background system Xiao Mingzu, aged 25.

If you use a third party queue, such as RabbitMQ or Kafka, then you don’t need to be concerned about the cache. If you use a third party queue, you don’t need to be concerned about the cache. If you use a third party queue, you don’t need to be concerned about the cache.

Of course, different solutions can also be used together, but there is no “silver bullet”, no perfect solution. It depends on your R & D team and which solution is suitable for your scene.

That’s all for today.