preface
It’s great to use caching to improve application performance, but what are the problems associated with using caching?
Let’s talk about what’s wrong with caching and how to deal with it
- Understand the problems that arise when systems use caching
- Understand solutions to common cache consistency problems
- Deal with cache penetration, cache breakdown, cache avalanche
Common problems with caching
Let’s review the process of using caching
The use of caching greatly improves the performance and efficiency of applications, especially data queries. But at the same time it also brings some problems, the most crucial of which is the data consistency problem
In a strict sense, there is no solution to this problem. Business scenarios with high requirements on real-time performance should not use caching, whereas to use caching should accept its inconsistencies
In addition to cache consistency issues, there are several typical problems encountered: cache penetration, cache breakdown, and cache avalanche
There are also popular solutions to common problems with caching
We’re not trying to perfect these problems, nor are we trying to subvert popular industry solutions
We want to understand some problems and solutions encountered in the use of cache
Cache consistency
Real-time data synchronization
This data synchronization is incremental, proactive, and highly consistent
-
When database data is updated (add, modify, delete), the cache is eliminated
-
Update the cache as data is read. Synchronization is needed to avoid an avalanche of cache breakdowns
Control a key and only one thread reads the data and then updates the cache, while the other threads block and wait
-
Set cache expiration time. This is a bottom-of-the-line operation. If the cache update fails, the cache will be invalidated as soon as the cache expiration time expires
The flow chart is as follows
Of course, this is only to ensure that the thread execution order is not out of order
If Clinet2 is executed too quickly and Clinet1 is not finished, the cached data is still inconsistent with the database
On-time data synchronization
This data synchronization is incremental, passive, and quasi-consistent
- Send an UPDATED CACHED MQ message after the data update operation (if you want to ensure that data is not lost, create a message table locally and retry after sending MQ failed)
- The cache update service consumes THE MQ update data message and reads the database data for relevant business processing
- The cache update service updates the business processing results to the cache
The flow chart is as follows
The core idea is to send a message to update the data over MQ to the cache update service, which reads the database data to update the cache
Task scheduling update
In this way, the cache is updated periodically by scheduling tasks, and the application scenario is as follows: report statistics data, reconciliation data is periodically updated to the cache and other scenarios where real-time performance is not high
The implementation is relatively simple
- The Timer or ScheduledExecutorService
- Spring Task Indicates a scheduled Task
- Periodic task framework Quartz or XXL-Job
The flow chart is as follows
The core idea is to update the cache by reading database data in a timed way, which will have a certain delay and can be considered in scenarios requiring less real-time performance
Binlog Log subscription
Update the cache by subscribing to binlog. The consumption service we build is a slave of mysql. Subscribe to binlog to parse the update content and then update it to the cache
The flow chart is as follows
Its process is very similar to task scheduling update, scheduled task is scheduled active update and log subscription is passive update
In this way, the performance is better and the consistency of cached data is better guaranteed
When mysql is under low pressure, its latency is relatively low, and it is completely decoupled from services, which also solves the real-time problem
Of course, the disadvantages are also obvious, the need to build a separate binlog client synchronization service, and the introduction of binlog synchronization mechanism, so that the cost will increase invisibly
The cache to penetrate
Cache penetration is a query for data that must not exist because the cache is not hit when the query is from the database
If the data is not found, it will not be written to the cache, which will result in the non-existent data being queried in the database on every request
In case of heavy traffic, DB may hang. If someone attacks our application frequently with non-existent key, it is a system vulnerability
The solution
- Verify the validity of request parameters based on service scenarios to prevent illegal requests from crushing the DB. Direct interception such as user ID <=0
- If db cannot query the data, save the empty object to the cache layer and set a short expiration time
- Bloom filters are used to store cached keys and filter out non-existent keys when access requests arrive, preventing these requests from reaching the DB level
Cache breakdown
Cache breakdown refers to data that is not in the cache but is present in the database.
At this time, due to a large number of concurrent requests, the cache does not read data at the same time
At the same time to the database query data, causing the database pressure increased instantly, resulting in excessive pressure
The solution
- If the cache data is not set to expire, there will be no hot key expiration resulting in a large number of requests to the database
- Add a mutex lock to ensure that only one request can access the database when the cache data fails, update the cache, and the other threads wait and retry
Cache avalanche
Cache avalanche refers to the fact that a large amount of data in the cache reaches the expiration time and a large amount of query data causes the database to become overburdened or even down
Unlike a cache breakdown, which refers to a concurrent query for the same data, a cache avalanche is when different data are out of date and a lot of data is not found and therefore the database is queried
The solution
- The expiration time of cache data is set randomly to prevent a large number of data from expiring at the same time
- If the cache database is deployed in a distributed manner, distribute the hotspot data evenly among different cache databases
- Set the hotspot data to never expire