Should I update the database first or the cache first?

Hello everyone, I am Glacier~~

Recently, my friends have been asking me recently, after the introduction of the cache in the system, when writing data to the database, should I write to the database first or write to the cache first? Is there any difference between writing to the database first and writing to the cache first? Today, we will talk about this topic together.

In essence, whether you write to the database first or write to the cache first, it is to ensure that the data in the database and the cache are consistent, which is what we often call data consistency.

With the rapid development of the Internet, the current era has entered the DT era from the IT era. The Internet system architecture has also changed from the initial monolithic architecture to a distributed, micro-service architecture model. From the perspective of data volume, the amount of data stored in each system is getting larger and larger, and the data query performance is getting lower and lower. At this point, we need to continue to optimize, a commonly used optimization method is to introduce caching. After the introduction of caching, when we insert data into the database, should we update the database first or update the cache first?

General use of cache

Caching, in essence, is an intermediate caching layer introduced to better coordinate two components with large differences in speed. For example, if you need to read data into the CPU for calculation processing, the calculation speed of the CPU is very fast, and the IO processing of the disk is many orders of magnitude slower than that of the CPU. Every time data is read from the disk, it will be Cause the CPU to wait for a long time and frequently for disk IO At this point, we can use memory to ease the speed difference between the CPU and the disk.

Insert picture description here

From the perspective of the use of the cache, the cache is generally used in accordance with the following process.

Insert picture description here
We can also express it as the following sequence diagram.

Insert picture description here

In the above usage example, we simply put the data in the cache, and set an expiration time for the cache at most. After the expiration, the cache will naturally be cleared, and subsequent requests will not get the data in the cache. Will get data from the database and write the data to the cache.

But in the subsequent data update operation, after updating the database, will the cache be updated or deleted? Or is it to delete the cache first, and then update the database?

Cache update strategy

In theory, setting an expiration time for the cache is actually a manifestation of eventual consistency. Under this scheme, an expiration time can be set for the data stored in the cache, all write operations are subject to the database, and only the best efforts are required for the cache operation. That is to say, if the database is successfully written and the cache update fails, as long as the expiration time is reached, subsequent read requests will naturally read the new value from the database and then backfill the cache. This is also the most commonly used method in general.

Update the database first and then update the cache

In fact, many experienced friends are very opposed to this scheme. Why, let's analyze it.

First of all, this solution will have thread safety issues.

For example, if thread A and thread B are updating data at the same time, the following execution sequence may occur.

(1) Thread A updated the database
(2) Thread B updated the database
(3) Thread B updated the cache
(4) Thread A updated the cache

At this time, there will be inconsistencies between the data in the database and the cached data. This is because thread A updates the database first. Maybe because of abnormal conditions such as the network, thread B updates the database and then updates the cache. When thread B updates the cache Later, thread A updates the cache, which leads to inconsistencies between the database data and the cache data.

Secondly, this solution also has its inapplicable business scenarios.

The first business scenario is a scenario where the database writes more and less reads. In this scenario, the strategy of updating the database first and then updating the cache will cause the cache to be updated frequently if it is not read, which greatly wastes the server's performance.

Another business scenario is that the data in the database is not directly written to the cache, but requires a lot of complex calculations to write the results of the calculations into the cache. If the strategy of updating the database first and then updating the cache is used in this scenario, server resources will also be wasted.

Delete the cache and then update the database

The solution of deleting the cache and then updating the database also has thread safety issues. For example, thread A updates the cache, while thread B reads the cached data. The following order of execution may appear.

(1) Thread A deletes the cache
(2) Thread B queries the cache and finds that there is no desired data in the cache
(3) Thread B queries the old data in the database
(4) Thread B writes the queried old data into the cache
(5) ) Thread A writes new data to the database

At this time, there is an inconsistency between the data in the database and the data in the cache. If the deletion of the cache fails, the database data and the cached data will also be inconsistent.

Update the database and then delete the cache

First of all, this method also has a very small probability of inconsistency between database data and cached data. For example, thread A performs a query operation and thread B performs an update operation. The order of execution is as follows.

(1) The cache just expires
(2) Request A to query the database and get the old value in the database
(3) Request B to write the new value to the database
(4) Request B to delete the cache
(5) Request the old value that A will find Write cache

If the above sequence occurs, it will cause inconsistency between the data in the database and the data in the cache.

However, the strategy of updating the database and then deleting the cache has a low probability of inconsistency between the database and the cached data. The reason is: (3) The write database operation takes less time than the read database operation of step (2), and it is possible to make the step (4) Execute before step (5). However, the read operation of the database is often much faster than the write operation, so step (3) takes less time than step (2), and this scenario is difficult to appear.

If the deletion of the cache fails, the database data and the cached data will also be inconsistent.

In this way, it seems that the three schemes are not safe, so what should we do? The ultimate goal is to introduce a retry mechanism.

Recommended Use

In the actual production environment, it is recommended to use to update the database and then delete the cache operation. So, how do we solve the problems under this strategy?

There are two solutions, one is to handle the failure retry operation in the program logic; in addition, with the help of Alibaba's open source Canal.

Manual failure retry

Insert picture description here

The process is as follows
(1) Update database data;
(2) Failed to delete cached data
(3) Send the key to be deleted to the message queue
(4) Consume the message by yourself, obtain the key that needs to be deleted
(5) Continue to retry the delete operation Until success

This scheme has a shortcoming, causing a lot of intrusion to the line of business code.

Synchronize database data

Let's first come to a picture, which solves the inconsistency of database data and cached data from the overall architecture.

Insert picture description here

The process is shown in the following figure:
(1) Update the database data
(2) The database writes the change information of the data table data into the binlog log
(3) The subscription program obtains the required data and key
(4) The specific business is processed in the program logic Logic, receive the request to subscribe to the binlog and initiate the deletion of the cache.
(5) Try to delete the cache operation and find that the deletion fails
(6) Send the information to the message queue
(7) Re-obtain the data from the message queue, and retry the operation.

Okay, let’s stop here today. I’m Glacier. If you have any questions, you can leave a message below, or add me to WeChat: sun_shine_lyz, I will pull you into the group, share technology together, advance together, and be awesome together~~

Guess you like

Origin blog.csdn.net/l1028386804/article/details/114994526