Caching?

When the client requests data, if it can hit the data in the cache, it queries the cache, and does not need to query the database, so as to reduce the pressure of the database and improve the performance of the server.

Due to the introduction of caching, when data is updated, not only the database is updated, but also the cache is updated. These two update operations have before and after problems:

  • Update the database first, then update the cache;
  • Update the cache first, then update the database;

Update the database first, then update the cache

Request A and request B update A data at the same time, the following order may occur:

A requests B to update the database to 1, then B to update the database to 2 before updating the cache, followed by B to update the cache to 2, and THEN A requests to update the cache to 1.

At this point, the data in the database is 2, but the data in the cache is 1. The data in the cache is inconsistent with the data in the database.

Update the cache first, then the database

Request A and request B update A data at the same time, the following order may occur:

A requests to update the cached data to 1, and then before updating the database, B requests to update the cached data to 2, followed by the database to 2, and THEN A requests to update the database to 1.

At this point, the data in the database is 1, but the data in the cache is 2, and the data in the cache and the database are inconsistent.

Therefore, either “update the database first, then update the cache” or “update the cache first, then update the database”, these two schemes have concurrency problems. When two requests concurrently update the same data, there may be data inconsistency between the cache and the database.

The solution

Instead of updating the cache, the data in the cache is deleted. Then, when the data is read and the cache is empty, the data is read from the database and updated into the cache.

The Cache value strategyIn Chinese, it is called bypass cache policy.

This strategy can be subdivided into “read strategy” and “write strategy”

Steps to write a policy:

  • Update data in the database;
  • Delete data from the cache.

Steps of the read strategy:

  • If the read hits the cache, the data is returned directly;
  • If the read data does not hit the cache, the data is read from the database, written to the cache, and returned to the user.

【 Write strategy 】 Which order to choose?

  • Delete the cache first, then update the database;
  • Update the database first, then delete the cache

Delete the cache first, then update the database

Let’s say some user is 20 years old, and request A updates the user to be 21 years old, so it deletes what’s in the cache. In this case, another request B wants to read the age of the user. After querying the cache and finding A miss, it will read the age of 20 from the database and write it to the cache. Then it asks A to continue to change the database and update the age of the user to 21

Finally, the user’s age is 20 in the cache (old value) and 21 in the database (new value), and the cache and database data are inconsistent.

As you can see, if you delete the cache first and then update the database, there will still be inconsistency between the cache and the database when the “read + write” concurrency occurs.

Update database first, then delete cache

If A user data does not exist in the cache, request A reads the data from the database to the age of 20. When the data is not written to the cache, another request B updates the data. It updates the age in the database to 21 and clears the cache. Request A to write the data aged 20 read from the database to the cache.

Finally, the user age is 20 in the cache (old value) and 21 in the database (new value), and the cache and database data are inconsistent.

From the above theoretical analysis, updating the database first and then deleting the cache will also lead to data inconsistency, but in practice, the probability of this problem is not high.

Because cache writes are usually much faster than database writes, it is very difficult in practice for request A to finish updating the cache after request B has updated the database and removed the cache.

If request A updates the cache before request B deletes it, subsequent requests will re-read the data from the database because of A cache miss, so this inconsistency does not occur.

Therefore, “update the database first + delete the cache later” scheme can ensure data consistency.

In order to be sure, the cache data is added with “expiration time”, even if there is inconsistency in the cache data during the expiration time, so that the final consistency can be achieved.

Will there be problems?

“Update the database first, then delete the cache” is actually two operations, all the previous analysis was based on the two operations can be successfully executed at the same time, but the customer complained about the problem is that the deletion of the cache (the second operation) failed, resulting in the cache data is old value.

How to ensure that the operations “update the database first, then delete the cache” can be performed successfully? “Update the database first, then delete the cache” ensures data consistency between the database and the cache, but the cached data will be deleted every time the data is updated, which affects the hit ratio of the cache.

Therefore, if our business has high requirements for cache hit ratio, we can adopt the “update database + update cache” solution, because updating the cache does not result in a cache miss.

But this plan before we also analysis in two update request concurrent execution, there will be a data inconsistency problem, because the update database and update the cache the two are independent operation, and we don’t have to do any operation and concurrency control, so when two threads concurrent update them, will be different because the write order cause data inconsistencies.

So we need to add some tools to solve this problem. Here are two ways to do it:

  • Add a distributed lock before updating the cache to ensure that only one request is run at the same time, and there will be no concurrency problems. Of course, the introduction of the lock will affect the performance of the write.
  • After updating the cache, add a short expiration time to the cache, so that even if the cache inconsistency occurs, the cached data will soon expire, which is acceptable for business.

The solution to cache inconsistency caused by “delete cache first, then delete database” in “read and write” concurrent requests is “Delayed double Deletion”

The pseudo-code of delayed double deletion is as follows:

Update (X) # redis.delkey (X) # redis.delkey (X) # redis.delkey (X) # redis.delkey (X) # redis.delkey (X) # redis.delkey (X)Copy the code

The pseudo-code of delayed double deletion is as follows:

Update (X) # redis.delkey (X) # redis.delkey (X) # redis.delkey (X) # redis.delkey (X) # redis.delkey (X) # redis.delkey (X)Copy the code

A sleep time is added, mainly to ensure that when request A is sleeping, request B can complete the operation of “reading data from the database and writing the missing cache to the cache” during this period, and then request A to finish sleeping and then delete the cache.

Therefore, request A needs to sleep longer than request B’s “read from database + write to cache” time.

However, the exact amount of sleep is a mystery and difficult to evaluate, so the solution is to ensure consistency as much as possible. In extreme cases, there will still be cache inconsistency.

Therefore, it is recommended to update the database first, then delete the cache.