preface
In April, a friend went to meituan for an interview. He said that he was asked how Redis and MySQL dual-write consistency can be guaranteed. How is the consistency of the cache and database guaranteed in the dual-write scenario? In this article, we will discuss how to answer this question.
- Public account: pick up the little boy snail
- Github address, thanks to each star
Talk about consistency
Consistency is the consistency of data. In a distributed system, it can be understood as the consistency of data values across multiple nodes.
- Strong consistency: This level of consistency is the most intuitive for the user. It requires the system to write and read what it says, which is a good user experience, but often has a significant impact on the performance of the system
- Weak consistency: This consistency level does not promise to read the value immediately after a write or how long it will take for the data to be consistent, but tries to ensure that the data will be consistent until a certain time level (such as seconds)
- Final consistency: Final consistency is a special case of weak consistency, where the system is guaranteed to reach a data consistency state over time. The reason why the final consistency is put forward separately here is that it is a highly respected consistency model in weak consistency, and it is also a highly respected model in the industry for data consistency in large distributed systems
Three classic caching patterns
Caching can improve performance and relieve database stress, but it can also lead to data inconsistency. How do we use caching in general? There are three classic caching modes:
- Cache-Aside Pattern
- Read-Through/Write through
- Write behind
Cache-Aside Pattern
Cache-aside Pattern, or the off-line Cache Pattern, is proposed to solve the inconsistency between the Cache and the database as much as possible.
Cache – value reading process
The cache-aside Pattern read request process is as follows:
- When reading, the cache is read first. If the cache hits, the data is returned directly
- If the cache doesn’t hit, it reads the database, retrives the data from the database, puts it in the cache, and returns a response.
Cache – value writing process
The process of a cache-aside Pattern write request is as follows:
When updating, first update the database and then delete the cache.
Read-through/write-through
In the Read/Write Through mode, the server uses the cache as the primary data store. The application interacts with the database cache through the abstract cache layer.
Read-Through
The read-through process is as follows
- Read data from cache, read to return
- If not, it loads it from the database, writes it to the cache, and returns a response.
Is this brief process similar to cache-aside? Read-Through is a layer of cache-provider. The process is as follows:
Read-Through is a layer of encapsulation over the cache-aside, which makes the code cleaner and reduces the load on the data source.
Write-Through
Write-ThroughMode, when a write request occurs, it is also made byCache abstraction layerComplete the update of data source and cache data. The process is as follows:
Write behind (asynchronous cache Write)
Write Behind is similar to read-through/write-through in that the Cache Provider is responsible for reading and writing data to the Cache and database. Read/Write Through updates the cache and data synchronously, while Write Behind updates only the cache, not the database directly, and updates the database asynchronously in batches.
In this mode, the consistency between the cache and the database is not strong. Therefore, use this method with caution on systems that require high consistency. However, it is suitable for frequent write scenarios, such as MySQL’s InnoDB Buffer Pool mechanism.
When you operate on the cache, do you delete the cache or update the cache?
In general business scenarios, we use cache-aside mode. Some people may ask, why does a cache-aside write request delete the Cache instead of updating it?
When we operate on the cache, should we delete or update the cache? Let’s start with an example:
- Thread A initiates A write operation, which updates the database first
- Thread B initiates another write operation, and the second step updates the database
- For network reasons, thread B updates the cache first
- Thread A updates the cache.
At this time, the cache stores A’s data (old data), and the database stores B’s data (new data). The data is inconsistent, and dirty data appears. This dirty data problem does not occur if the delete cache replaces the update cache.
Updating caches has two disadvantages over deleting caches:
- If you’re writing to a cache value that has to be calculated. Updating the cache too often wastes performance.
- In scenarios where there is a lot of write to the database and a lot of read to the database, the data will be updated before it is read, which is a waste of performance (in fact, in scenarios where there is a lot of write, caching is not very cost-effective).
In the case of double – write, does the database or the cache come first?
In the cache-aside mode, some people still have questions, when writing a request, why is the database first? Why not work with the cache first?
Suppose there are two requests from A and B. A is asked to perform update operation and B is asked to perform query read operation.
- Thread A initiates A write operation, starting with del cache
- Thread B initiates a read operation and the cache miss occurs
- Thread B continues to read DB, reading out an old data
- Thread B then sets the old data to cache
- Thread A writes the latest data from DB
The cache and database data are inconsistent. The cache holds old data, and the database holds new data. Therefore, the cache-aside mode chooses to work with the database rather than the Cache first.
Cache delay double delete
Some people might say, you don’t have to operate the database first, just use the cache delay dual-delete strategy, okay? What is delayed deduplication?
- Delete the cache first
- Update the database again
- Sleep for a moment (say 1 second) and delete the cache again.
This is dormant for a while. How long is it usually? They’re both 1 second, right?
This sleep time = time taken to read the business logic data + several hundred milliseconds. To ensure the end of the read request, the write request can remove any cache dirty data that may have been generated by the read request.
The cache retry mechanism was deleted
If the second step fails to delete the Cache, dirty data will be caused
If you fail to delete the cache, you can delete it several times to ensure that the cache is successfully deleted
- The write request updates the database
- The cache failed to be deleted for some reason
- Put the failed deletion key on the message queue
- Consume the message from the message queue and get the key to delete
- Try deleting the cache again
Read BigLog and asynchronously delete the cache
Retry to delete the cache mechanism is ok, but will cause a lot of business code intrusion. In fact, you can also asynchronously eliminate keys through the database’s binlog.
Taking mysql as an example, Ali’s Canal can be used to collect binlog logs and send them to the MQ queue. Then, the UPDATE message can be confirmed and processed through ACK mechanism, and the cache can be deleted to ensure the consistency of data cache
Reference and Thanks
- In a concurrent environment, does the database or the cache come first?
- In high concurrency scenarios, should you update the cache or the database first?
- A dilemma! Update the database before deleting the cache? Or delete the cache first and then update the database?
- Don’t know any of the three cache read and write policies? It’s hard to get you through the interview, man